home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 2000 August: Tool Chest / Dev.CD Aug 00 TC Disk 2.toast / pc / sample code / interapplication comm / coresample / coresample.c < prev    next >
Encoding:
Text File  |  2000-06-23  |  85.5 KB  |  2,324 lines

  1. /*
  2.     File:        CoreSample.c
  3.  
  4.     Contains:    An application that is Apple Event-aware, Scripting Compatible,        
  5.                 and recordable. It supports the Required and Core Suite of             
  6.                 Apple Events, the Object Model, and the Open Scripting                
  7.                 Architecture.
  8.                                                                                                     
  9.                 The main purpose of this sample code is to demonstrate how to develop an             
  10.                 application that is Apple event-aware, scripting compatible, uses the Object        
  11.                 Support Library, and supports Apple's Open Scripting Architecture.  In                 
  12.                 addition, it has its own 'aete' (Apple Event Terminology Extension) resource        
  13.                 (CoreSampleAETE.r). By    incorporating these technologies into your application,    
  14.                 your application will support Apple's Open Scripting Architecture.                    
  15.                                                                                         
  16.                 The functionality of CoreSample is basic window manipulation. The user may            
  17.                 create, drag, size, zoom, and close windows.  All these actions    may be                
  18.                 performed through Apple events.                                                        
  19.                                                                                             
  20.                 This application is also "factored", which means that user interactions (such        
  21.                 as dragging or sizing a window, selecting a menuitem) are converted into Apple        
  22.                 events which the application sends off to itself, and then is handled by the        
  23.                 corresponding event handler.  Factoring makes it possible to access the appli-        
  24.                 cation's functionality through Apple events. It also makes it easier to record        
  25.                 the user's actions in the form of Apple events.                                        
  26.                                                                                             
  27.                 CoreSample supports the Required and Core suites of events, and the application        
  28.                 and window object classes. One additional property has been added to the window     
  29.                 class, and that is its position, the top left-hand coordinates of the window.        
  30.                 Some events only apply to the window class, such as Create, Move, Clone, and         
  31.                 Set Data (application properties are not modifiable, except for pClipboard,         
  32.                 which I do not support).  Currently, CoreSample supports the Simple Grammar,        
  33.                 as defined in the "Object Support Library Developer Note".                            
  34.                                                                                             
  35.                 The properties you may access with the Get Data Apple event are as follows:            
  36.                     Application - Best Type, Default Type, Class, Name, IsFrontProcess, Version        
  37.                     Window - Best Type, Default Type, Bounds, Class, Index, Name, Position,            
  38.                      Closeable, Titled, Resizable, Zoomable, Floating, Modal, Zoomed,        
  39.                      and Visible.                                                            
  40.                 The properties you may set with the Set Data Apple event are as follows:            
  41.                     Window - Bounds, Index, Zoomed, Name, Position, and Visible.                    
  42.                                                                                             
  43.                 When you create a new element, you may pass it initial data values. This            
  44.                 application will create the    new element accordingly if either or both of the        
  45.                 initial data parameters exist. In addition, with CoreSample, you may create or        
  46.                 move a window without passing it an insertion location record. By default, a        
  47.                 window will be created/moved to the frontmost position.                                
  48.                                                                                             
  49.                 (NOTE: Some portions of this code are derived from TESample, a                        
  50.                 sample application provided by Apple Developer Technical Support.)                    
  51.  
  52.     Written by:    Sue Dumont     
  53.  
  54.     Copyright:    Copyright © 1992-1999 by Apple Computer, Inc., All Rights Reserved.
  55.  
  56.                 You may incorporate this Apple sample source code into your program(s) without
  57.                 restriction. This Apple sample source code has been provided "AS IS" and the
  58.                 responsibility for its operation is yours. You are not permitted to redistribute
  59.                 this Apple sample source code as "Apple sample source code" after having made
  60.                 changes. If you're going to re-distribute the source, we require that you make
  61.                 it clear in the source that the code was descended from Apple sample source
  62.                 code, but that you've made changes.
  63.  
  64.     Change History (most recent first):
  65.                 7/21/1999    Karl Groethe    Updated for Metrowerks Codewarror Pro 2.1
  66.                 12/1/93        <dan>            added PowerPC support - will run native on PowerPC if     
  67.                                             compiled on PowerPC system.    These changes are denoted        
  68.                                             by [pwpc].
  69.                 6/22/93      <doo>            converted files to run in the Think C 6.0 environment    
  70.                                             Fixed incorrect comparison of rects and windowlist problems    
  71.                                             associated with the Think compiler.    
  72.                 4/02.93      <smd>            added GetWindowBounds routine to calculate the correct    
  73.                                             bounds when the bounds accessed from the content region is    
  74.                                             invalid (such as when the application is hidden).                
  75.                                         -    cleaned up the aete.
  76.                 10/01/92      <smd>             Added pVersion to application and now set the port before    
  77.                                             setting the pPosition property.        
  78.                 07/19/92      <smd>            Fixed bug where the Move event was not recording the    
  79.                                             correct window being moved when the data was being passed    
  80.                                             by index rather than by name.    
  81.                 04/30/92      <smd>            Check if replacing the same window in HandleMove    
  82.                                             (i.e., "move window 2 to window 2"). If so, do nothing.        
  83.                 06/25/92      <smd>            Changed FindRelativeWindow to return the windowPtr of the        
  84.                                             window being replaced rather than closing it. This caused        
  85.                                             an error when trying to replace the same window, in which        
  86.                                             case nothing should happen. (Ex. move window 2 to window 2).
  87.                 04/27/92      <smd>            Fixed bug in DoSetData where data was set to a pointer, and    
  88.                                             then the pointer was diposed of.
  89.                 04/20/92      <smd>             Fixed a bug with setting the visibility property of a window.
  90.                 02/28/92      <smd>            Added coercion routines (thanks Kevin) to clean up code.    
  91.                                             These convert from descs to boolean, long, and pstrings.
  92.                 02/25/92      <smd>            Modified GetWindowWithTitle, GetWidnowWithIndex, and    
  93.                                             GetWindowIndexNum routines to use WindowList so ALL windows        
  94.                                             will be accessed (even invisible ones).                            
  95.                                          -    Changed InitializeDescs to MyInitDescs and DisposeDescs to    
  96.                                             MyDisposeDescs.                                                    
  97.                                          -    Removed the FailIfErr calls from the AE Handlers so that        
  98.                                             they will return the error code rather than dying.
  99.                 02/24/92      <smd>            Now sends a Move event when just making a window active.    
  100.                                             This is done in the DoEvent routine, drag region.
  101.                 02/21/92      <smd>            Fixed bug where the same AEDesc was being passed as source    
  102.                                             and dest to AECoerceDesc().                                        
  103.                                             Send myself a Move event when user clicks in content of a        
  104.                                             window.
  105.                 02/17/92      <smd>            Added InitializeDescs() and DisposeDescs() routines.    
  106.                 02/05/92      <smd>            Handling optional parameters in Create Element event.
  107.                 01/30/92      <smd>            Adding complete support for core suite and properties.
  108.                 01/21/92      <smd>            Positive and negative offset when referencing by index.
  109.                 01/10/92      <smd>            Made insertion location parameter optional in the Create
  110.                                             and Move events, and provided my own default behavior.    
  111.                 01/09/92      <kc>            Quick clean up for Scripting QuickStart.        
  112.                 01/06/92      <kc>            Added code for Count Elements, Do Objects Exist, Move,
  113.                                             and Get Data Size
  114.                 11/91          <smd>            Initial code implementation.                    
  115.  
  116. */
  117. #include    <Types.h>
  118. #include     <Quickdraw.h>
  119. #include     <Events.h>
  120. #include     <AppleEvents.h>
  121. #include     <AEObjects.h>
  122. #include     <AEPackObject.h>
  123. #include    <Resources.h>                    // for version resource
  124. #include     <Windows.h>
  125. #include     <Menus.h>
  126. #include     <Dialogs.h>
  127. #include     <Desk.h>
  128. #include     <Scrap.h>
  129. #include    <limits.h>
  130. #include     <ToolUtils.h>
  131. #include     <Memory.h>
  132. #include     <SegLoad.h>
  133. #include     <OSUtils.h>
  134. #include     <OSEvents.h>
  135. #include     <DiskInit.h>
  136. #include     <Packages.h>
  137. #include     <Traps.h>
  138. #include    <string.h>
  139. #include    <Strings.h>
  140. #include    <stdarg.h>
  141. #include    "AERegistry.h"                // Constants defined in the Registry.
  142. #include     "CoreSample.h"
  143. #include     <LowMem.h>
  144.  
  145. #define HiWrd(aLong)    (((aLong) >> 16) & 0xFFFF)
  146. #define LoWrd(aLong)    ((aLong) & 0xFFFF)
  147.  
  148. typedef  long*            LongPtr;
  149. typedef  WindowPeek*    PeekPtr;
  150.  
  151.     //    Globals.
  152. SysEnvRec        gMac;                    // Contains the system environment
  153. Boolean            gHasWaitNextEvent;        // True if WaitNextEvent trap is available
  154. Boolean            gInBackground;            // Determines if currently in the background
  155. long            gNumWindowsOpen;        // The number of windows open
  156. short            gNewWindows;            // The number of new windows created
  157. Boolean            gQuitApp;                // True to quit the application
  158. AEDesc            gNullDesc;                // A null descriptor record
  159. AEAddressDesc    gSelfAddress;            // A self-addressed address descriptor record
  160. ProcessSerialNumber    gSelfPSN;            // This application's psn
  161. short            gRefNum;                // reference number of rescource file
  162.  
  163.  
  164. //----------------------------------------------------------------------------------//
  165. //            PROTOTYPES                                                                //
  166. //----------------------------------------------------------------------------------//
  167. void        AdjustMenuStates(void);
  168. void        AlertUser(short error);
  169. void        CloseTheWindow(WindowPtr window);
  170. WindowPtr    DoCreateNewWindow(WindowPtr behind);
  171. OSErr        CreateWindowObjectSpec(WindowPtr window,short formType,AEDesc *objectSpec);
  172. void        DoEvent(EventRecord *event);
  173. void        DoGrowWindow(WindowPtr window, EventRecord *event);
  174. void        DoMenuCommand(long menuResult);
  175. OSErr         DoSetData(AEDesc *token, AEDesc *data);
  176. void        DoUpdate(WindowPtr window);
  177. void        EventLoop(void);
  178. void        FailIfErr(OSErr error);
  179. OSErr        FindRelativeWindow(WindowPtr *window,AEDesc *object,DescType pos,WindowPtr *replaceWindow);
  180. OSErr        GetAppData(DescType theProperty, AEDesc *result);
  181. OSErr        GetMissingParams(AppleEvent *theAppleEvent);
  182. OSErr        GetWindowData(DescType property, WindowPtr window, AEDesc *result);
  183. long        GetWindowIndexNum(WindowPtr window);
  184. WindowPtr    GetWindowAtIndex(long index);
  185. WindowPtr    GetWindowWithTitle(ConstStr255Param title);
  186. void        InitAEHandlers(void);
  187. void        Initialize(void);
  188. Boolean     IsAppWindow(WindowPtr window);
  189. Boolean     IsDAWindow(WindowPtr window);
  190. Boolean     IsTrapAvailable(short tNumber, TrapType tType);
  191. void        ReportError(AppleEvent *reply, long err);
  192. WindowPtr    ResolveToWindow(AEDesc *objectSpecifier);
  193. void        SendClose(WindowPtr  window);
  194. void        SendCreateElement(void);
  195. void        SendMoveEvent(WindowPtr windowToMove, long index);
  196. void        SendQuitApp(void);
  197. void         SendSetData(AEDesc *pDesc, AEDesc *pData, AEDesc *object);
  198. void        SetUpPropertyData(WindowPtr window,DescType propType,DescType dataType,Size dataSize);
  199. void        SignalError(short error);
  200. void        Terminate(void);
  201. void        ZoomIt(WindowPtr window, short part);
  202. Rect        DoGetWindowBounds(WindowPtr window);
  203. void         MakeNewWindowTitle( short        num,                // Window number.
  204.                          Str255        title);
  205. void         MyInitDescs(AEDesc*  desc1, ... );
  206. void         MyDisposeDescs(AEDesc*  desc1, ... );
  207. OSErr         DescToBoolean(const AEDesc* desc, Boolean* boolvalue);
  208. OSErr         DescToLong(const  AEDesc* desc, long* longvalue);
  209. OSErr         DescToPString(const AEDesc* desc, Str255 str, short maxLength);
  210. pascal OSErr HandleOpenApp(AppleEvent *theAppleEvent, AppleEvent* reply, long refCon);
  211. pascal OSErr HandleQuitApp(AppleEvent* theAppleEvent, AppleEvent* reply, long refCon);
  212. WindowPtr     DoCloneWindow(WindowPtr windowToClone, WindowPtr behindWindow);
  213. pascal    OSErr HandleClone(AppleEvent* theAppleEvent, AppleEvent* reply, long refCon);
  214. pascal    OSErr HandleClose(AppleEvent* theAppleEvent, AppleEvent* reply, long refCon);
  215. pascal    OSErr HandleCountElements(AppleEvent* theAppleEvent, AppleEvent* reply, long refCon);
  216. pascal    OSErr HandleCreateElement(AppleEvent* theAppleEvent, AppleEvent* reply, long refCon);
  217. pascal    OSErr HandleDoObjectsExist(AppleEvent* theAppleEvent, AppleEvent* reply, long refCon);
  218. pascal    OSErr HandleSetData(AppleEvent* theAppleEvent, AppleEvent* reply, long refCon);
  219. pascal    OSErr HandleGetData( AppleEvent*    theAppleEvent,
  220.                      AppleEvent*    reply,
  221.                      long            refCon    );
  222. pascal    OSErr HandleMove(AppleEvent* theAppleEvent, AppleEvent* reply, long refCon);
  223. pascal    OSErr DummyHandler( AppleEvent        *theAppleEvent,
  224.                     AppleEvent        *reply,
  225.                     long            refCon    );
  226. pascal    OSErr WindowAccessor( DescType        classWanted,        // window class
  227.                       AEDesc*        container,            // the application (null container)
  228.                       DescType        containerClass, 
  229.                       DescType        keyform,
  230.                       AEDesc*        selectionData,
  231.                       AEDesc*        resultToken,        // specified window is returned in result
  232.                       long             theRefCon     );
  233. pascal    OSErr WindowPropertyAccessor( DescType        classWanted,        // Property class
  234.                                 AEDesc*        container,            // Window object
  235.                               DescType        containerClass, 
  236.                               DescType        form,
  237.                               AEDesc*        selectionData,
  238.                               AEDesc*        resultToken,
  239.                               long             theRefCon     );
  240. pascal    OSErr AppPropertyAccessor(    DescType        classWanted,            // Property class.
  241.                               AEDesc*            container,                // Application.
  242.                             DescType        containerClass, 
  243.                             DescType        form,
  244.                             AEDesc*            selectionData,
  245.                             AEDesc*            resultToken,
  246.                             long             theRefCon     );
  247. extern pascal OSErr CreateObjSpecifier(DescType theClass, AEDesc *theContainer,
  248.                         DescType keyForm, AEDesc *keyData, Boolean disposeInputs, 
  249.                         AEDesc *objSpecifier);
  250. extern void _DataInit();
  251.  
  252.  
  253. //----------------------------------------------------------------------------------//
  254. #pragma segment Main
  255. void main()
  256. {
  257. #ifndef THINK_C
  258.     UnloadSeg((Ptr) _DataInit);        // Note that _DataInit must not be in Main!
  259. #endif
  260.  
  261.     MaxApplZone();                    // Expand the heap so code segments load at the top.
  262.     Initialize();                    // Initialize the program
  263.     
  264. #ifndef THINK_C                        // Initialize the program
  265.     UnloadSeg((Ptr)Initialize);        // Note that Initialize must not be in Main!
  266. #endif
  267.  
  268.     EventLoop();                    // Call the main event loop
  269. }
  270.  
  271. //----------------------------------------------------------------------------------//
  272. // Continue retrieving events until the application terminates.                        //
  273. //----------------------------------------------------------------------------------//
  274. #pragma segment Main
  275. void EventLoop()
  276. {
  277.     RgnHandle        cursorRgn;
  278.     Boolean            gotEvent;
  279.     EventRecord        event;
  280.  
  281.     cursorRgn = NewRgn();
  282.     gQuitApp = false;                // This is set to true in Terminate().        
  283.     
  284.     while (!gQuitApp)                // Loop until user quits or error.
  285.     {
  286.         if (gHasWaitNextEvent)
  287.             gotEvent = WaitNextEvent(everyEvent, &event, LONG_MAX, cursorRgn);
  288.         else 
  289.         {
  290.             SystemTask();
  291.             gotEvent = GetNextEvent(everyEvent, &event);
  292.         }
  293.         if (gotEvent)
  294.             DoEvent(&event);
  295.     }
  296. }
  297.  
  298. //----------------------------------------------------------------------------------//
  299. //    Find out which event this is and send it off to its appropriate handler.        //
  300. //    When the user clicks in the drag region, either one of two events may be        //
  301. //    triggered. The set position property (set data event) would occur if the widnow //
  302. //    is dragged to another location, or the move event would be sent if the window    //
  303. //    is just made active. In the latter case, the window's index before being        //
  304. //    moved to the front is passed to SendMoveEvent for recording purposes.            //
  305. //----------------------------------------------------------------------------------//
  306. #pragma segment Main
  307. void DoEvent( EventRecord*  event )
  308. {
  309.     long        index=0;
  310.     short        part, err;
  311.     WindowPtr    window;
  312.     char        key;
  313.     Rect        bounds1, bounds2;
  314.     Point        aPoint;
  315.  
  316.     switch (event->what)
  317.     {
  318.         case mouseDown:
  319.             part = FindWindow(event->where, &window);
  320.             switch (part) 
  321.             {
  322.                 case inMenuBar:
  323.                     AdjustMenuStates();            
  324.                     DoMenuCommand(MenuSelect(event->where));
  325.                     break;
  326.                     
  327.                 case inSysWindow:
  328.                     SystemClick(event, window);
  329.                     break;
  330.                     
  331.                 case inContent:
  332.                     if (window != FrontWindow()) 
  333.                         SendMoveEvent(window, index);
  334.                     break;
  335.                     
  336.                 case inDrag:
  337.                     index = GetWindowIndexNum(window);
  338.                     bounds1 = (*((WindowPeek)window)->contRgn)->rgnBBox;
  339.                     DragWindow(window, event->where, &qd.screenBits.bounds);
  340.                     bounds2 = (*((WindowPeek)window)->contRgn)->rgnBBox;
  341.                     if ((bounds1.left == bounds2.left) && 
  342.                             (bounds1.top == bounds2.top))
  343.                         SendMoveEvent(GetWindowAtIndex(index), index);
  344.                     else
  345.                         SetUpPropertyData(window,pPosition,typeQDPoint,sizeof(Point));
  346.                     break;
  347.                     
  348.                 case inGoAway:
  349.                     if (TrackGoAway(window, event->where))
  350.                         SendClose(window);
  351.                     break;
  352.                     
  353.                 case inGrow:
  354.                     DoGrowWindow(window, event);
  355.                     break;
  356.                     
  357.                 case inZoomIn:                            // For recording purposes, we send an Apple
  358.                 case inZoomOut:                            // event to ourselves to set the bounds property.
  359.                     if (TrackBox(window, event->where, part))
  360.                     {
  361.                         ZoomIt(window, part);
  362.                         SetUpPropertyData(window, pIsZoomed, typeBoolean, sizeof(Boolean));
  363.                     }
  364.                     break;
  365.             }
  366.             break;
  367.             
  368.         case keyDown:
  369.         case autoKey:                               // Only handle menu key equivalents
  370.             key = event->message & charCodeMask;
  371.             if (event->modifiers & cmdKey)        // Command key down
  372.             {
  373.                 if (event->what == keyDown) 
  374.                 {
  375.                     AdjustMenuStates();                // Enable/disable/check menu items properly
  376.                     DoMenuCommand(MenuKey(key));
  377.                 }
  378.             } 
  379.             break;
  380.             
  381.         case activateEvt:
  382.             DrawGrowIcon((WindowPtr)event->message);
  383.             break;
  384.             
  385.         case updateEvt:
  386.             DoUpdate((WindowPtr) event->message);
  387.             break;
  388.             
  389.         case diskEvt:
  390.             if (HiWord(event->message) != noErr)
  391.             {
  392.                 SetPt(&aPoint, kDILeft, kDITop);
  393.                 err = DIBadMount(aPoint, event->message);
  394.             }
  395.             break;
  396.             
  397.         case kOSEvent:
  398.             {
  399.                 switch ((event->message >> 24) & 0x0FF)            // High byte of message.
  400.                 {
  401.                     case kMouseMovedMessage:
  402.                         break;                        // Do nothing if mouse moved.
  403.                     
  404.                     case kSuspendResumeMessage:        // suspend/resume is also an activate/deactivate
  405.                         SetCursor(&qd.arrow);
  406.                         if (IsAppWindow(window = FrontWindow()))
  407.                             DrawGrowIcon(window);
  408.                         break;
  409.                 }
  410.             }
  411.             break;
  412.             
  413.         case kHighLevelEvent:                        // Let the Apple Event Manager handle high level event.
  414.             AEProcessAppleEvent(event);
  415.             break;
  416.  
  417.         default:
  418.             break;
  419.     }
  420. }
  421.  
  422. //----------------------------------------------------------------------------------//
  423. //    Handle the mouseDown event in the grow box region of the window.  If the         //
  424. //    window has been resized, an Apple Event is sent to set the bounds property.        //
  425. //    This is done for recording purposes.                                            //
  426. //----------------------------------------------------------------------------------//
  427. #pragma segment Main
  428. void DoGrowWindow(    WindowPtr     window,
  429.                     EventRecord* event    )
  430. {
  431.     long            result;
  432.     Rect            tempRect;
  433.  
  434.     tempRect = qd.screenBits.bounds;        // Set up the limiting values.
  435.     tempRect.top = kMinWinDim;
  436.     tempRect.left = kMinWinDim;
  437.     result = GrowWindow(window, event->where, &tempRect);
  438.     if (result)                            // Did window actually change size?
  439.     {
  440.         SetPort(window);
  441.         InvalRect(&window->portRect);
  442.         SizeWindow(window, LoWrd(result), HiWrd(result), true);
  443.         InvalRect(&window->portRect);        // Send event for recording purposes.
  444.         SetUpPropertyData(window, pBounds, typeQDRectangle, sizeof(Rect));
  445.     }
  446. }
  447.  
  448. //----------------------------------------------------------------------------------//
  449. //    Zoom the window and set the refcon field to reflect its zoomed state.            //
  450. //----------------------------------------------------------------------------------//
  451. #pragma segment Main
  452. void ZoomIt( WindowPtr    window,
  453.              short        part  )
  454. {
  455.     SetPort(window);
  456.     EraseRect(&window->portRect);            // We just have a blank window.
  457.     ZoomWindow(window, part, window == FrontWindow());
  458.     SetWRefCon(window, (long)part == inZoomOut);    // Set to true if zoomed.
  459.     InvalRect(&window->portRect);
  460. }
  461.  
  462. //----------------------------------------------------------------------------------//
  463. //    This is called when an update event is received for a window.                    //
  464. //----------------------------------------------------------------------------------//
  465. #pragma segment Main
  466. void DoUpdate( WindowPtr  window )
  467. {
  468.     if (IsAppWindow(window)) 
  469.     {
  470.         BeginUpdate(window);
  471.         SetPort(window);
  472.         EraseRect(&window->portRect);            // We just have an empty window.
  473.         DrawGrowIcon(window);
  474.         EndUpdate(window);
  475.     }
  476. }
  477.  
  478. //----------------------------------------------------------------------------------//
  479. //    Set up the menus according to the current state.                                //
  480. //----------------------------------------------------------------------------------//
  481. #pragma segment Main
  482. void AdjustMenuStates()
  483. {
  484.     WindowPtr        window;
  485.     MenuHandle        menu;
  486.  
  487.     window = FrontWindow();
  488.     menu = GetMenuHandle(mFile);
  489.     if (gNumWindowsOpen < kMaxOpenWindows)
  490.         EnableItem(menu, iNew);            // Enable New if we can open more windows.
  491.     else
  492.         DisableItem(menu, iNew);
  493.     if (window)
  494.         EnableItem(menu, iClose);        // Enable Close if there is a window to close.
  495.     else
  496.         DisableItem(menu, iClose);
  497. }
  498.  
  499. //----------------------------------------------------------------------------------//
  500. //    This is called when an item is chosen from the menu bar.                        //
  501. //----------------------------------------------------------------------------------//
  502. #pragma segment Main
  503. void DoMenuCommand(long  menuResult)
  504. {
  505.     short        menuID, menuItem;
  506.     short        itemHit, daRefNum;
  507.     Str255        daName;
  508.     WindowPtr    window;
  509.  
  510.     window = FrontWindow();
  511.     menuID = HiWord(menuResult);
  512.     menuItem = LoWord(menuResult);
  513.     switch (menuID)
  514.     {
  515.         case mApple:
  516.             switch (menuItem) 
  517.             {
  518.                 case iAbout:
  519.                     itemHit = Alert(rAboutAlert, nil);
  520.                     break;
  521.                 default:            // all other items in this menu are DA's.
  522.                     GetMenuItemText(GetMenuHandle(mApple), menuItem, daName);
  523.                     daRefNum = OpenDeskAcc(daName);
  524.                     break;
  525.             }
  526.             break;
  527.             
  528.         case mFile:
  529.             switch (menuItem)                // All these items send Apple events to
  530.             {                                // handle the selection.
  531.                 case iNew:
  532.                     SendCreateElement();
  533.                     break;
  534.                 case iClose:
  535.                     SendClose(FrontWindow());
  536.                     break;
  537.                 case iQuit:
  538.                     SendQuitApp();
  539.                     break;
  540.             }
  541.             break;
  542.         
  543.         case mEdit:                    // Call SystemEdit for DA editing & MultiFinder.
  544.             SystemEdit(menuItem-1);
  545.             break;
  546.     }
  547.     HiliteMenu(0);                    // Unhighlight what MenuSelect (or MenuKey) hilited.
  548. }
  549.  
  550. //----------------------------------------------------------------------------------//
  551. //    This routine appends the ascii representation of num to the title string.        //
  552. //----------------------------------------------------------------------------------//
  553. #pragma segment Main
  554. void MakeNewWindowTitle( short        num,                // Window number.
  555.                          Str255        title)                // Window title.
  556. {
  557.     short        i, count, index;
  558.     char        numStr[5];
  559.     
  560.     i = 0;
  561.     do {
  562.             numStr[i++] = num % 10 + '0';
  563.         } while (num /= 10);
  564.         
  565.     index = title[0] + 1;                    // Get length of title string.
  566.     
  567.     for (count = i-1; count >= 0; count--)
  568.         title[index++] = numStr[count];
  569.     title[0] += i;
  570. }        
  571.  
  572. //----------------------------------------------------------------------------------//
  573. //    Create a new window behind the given window.  Use the window's refCon            //
  574. //    field to indicate whether the window is zoomed or not.                            //
  575. //----------------------------------------------------------------------------------//
  576. #pragma segment Main
  577. WindowPtr DoCreateNewWindow(WindowPtr behindWindow)
  578. {
  579.     Ptr            storage;
  580.     WindowPtr    newWindow, firstWindow;
  581.     Rect        bounds;
  582.     Str255        title;
  583.  
  584.     if (gNumWindowsOpen < kMaxOpenWindows)
  585.     {
  586.         storage = NewPtr(sizeof(WindowRecord));
  587.         if (storage != nil) 
  588.         {
  589.             newWindow = GetNewWindow(rDocWindow, storage, behindWindow);
  590.             if (newWindow != nil)
  591.             {
  592.                 gNumWindowsOpen++;            // Increment the number of windows currently open.
  593.                 gNewWindows++;                // Increment the number of new windows created.
  594.                 GetWTitle(newWindow, title);
  595.                 MakeNewWindowTitle(gNewWindows, title);
  596.                 SetWTitle(newWindow, title);
  597.                 if (firstWindow = FrontWindow())
  598.                 {
  599.           //•••            bounds = (*((WindowPeek)firstWindow)->contRgn)->rgnBBox;
  600.                     bounds = DoGetWindowBounds(firstWindow);
  601.                     MoveWindow(newWindow, bounds.left+30, bounds.top+30, false);
  602.                 }
  603.                 SetWRefCon(newWindow, 0L);            // set zoom state to false.
  604.                 SetPort(newWindow);
  605.                 return(newWindow);
  606.             }
  607.         else
  608.             DisposePtr(storage);        // Dispose of the storage if it is not used.
  609.         }
  610.     }
  611.     return(nil);
  612. }
  613.  
  614. //----------------------------------------------------------------------------------//
  615. //    Close the given window or desk accessory.                                        //
  616. //----------------------------------------------------------------------------------//
  617. #pragma segment Main
  618. void CloseTheWindow(WindowPtr  window)
  619. {
  620.     if (IsDAWindow(window))
  621.         CloseDeskAcc(((WindowPeek)window)->windowKind);
  622.     else 
  623.         if (IsAppWindow(window))
  624.         {
  625.             CloseWindow(window);
  626.             DisposePtr((Ptr)window);
  627.             gNumWindowsOpen--;
  628.         }
  629. }
  630.  
  631. //----------------------------------------------------------------------------------//
  632. //    Returns true if the window belongs to this application, else false.                //
  633. //----------------------------------------------------------------------------------//
  634. #pragma segment Main
  635. Boolean IsAppWindow(WindowPtr  window)
  636. {
  637.     if (!window)
  638.         return(false);
  639.     else 
  640.         return(((WindowPeek)window)->windowKind == userKind);
  641. }
  642.  
  643. //----------------------------------------------------------------------------------//
  644. //    Returns true if the given window belongs to a DA, else false is returned.        //
  645. //----------------------------------------------------------------------------------//
  646. #pragma segment Main
  647. Boolean IsDAWindow(WindowPtr  window)
  648. {
  649.     if (window == nil)
  650.         return(false);
  651.     else                    // DA windows have negative windowKinds.
  652.         return(((WindowPeek)window)->windowKind < 0);
  653. }
  654.  
  655. //----------------------------------------------------------------------------------//
  656. //  If an error has occurred, I check the user interaction level. If I can            //
  657. //    interact with the user, I put up a dialog and exit the application; otherwise,    //
  658. //    I just exit the application.                                                    //
  659. //                                                                                    //
  660. //    ***NOTE: Real applications would not handle errors in this fashion!  If they    //
  661. //    cannot interact with the user, they should abort the Apple event handler and    //
  662. // return the error in the reply parameter.                                            //
  663. //----------------------------------------------------------------------------------//
  664. #pragma segment    Main
  665. void FailIfErr(OSErr  error)
  666. {
  667.     if (error)
  668.     {
  669.         if (!(AEInteractWithUser(kNoTimeOut, nil, nil)))            // Can we interact?
  670.             AlertUser(eAEError);                                    // Yes, so put up the dialog.
  671.         ExitToShell();
  672.     }
  673. }
  674.  
  675. //----------------------------------------------------------------------------------//
  676. //    Display an alert for the user to indicate that an error has occurred.            //
  677. //----------------------------------------------------------------------------------//
  678. #pragma segment Main
  679. void AlertUser(short  error)
  680. {
  681.     short        itemHit;
  682.     Str255        message;
  683.  
  684.     GetIndString(message, kErrStrings, error);
  685.     ParamText(message, (ConstStr255Param)"\p", (ConstStr255Param)"\p", (ConstStr255Param)"\p");    // [pwpc]
  686.     itemHit = Alert(rUserAlert, nil);
  687. }
  688.  
  689. //----------------------------------------------------------------------------------//
  690. //    Quit the application by closing all windows and setting the quit flag to true.    //
  691. //----------------------------------------------------------------------------------// 
  692. #pragma segment Main
  693. void Terminate()
  694. {
  695.     WindowPtr    aWindow;
  696.  
  697.     while(aWindow = FrontWindow())
  698.         CloseTheWindow(aWindow);
  699.       AEDisposeDesc(&gSelfAddress);            // Dispose of my self-addressed descriptor.
  700.     gQuitApp = true;
  701. }
  702.  
  703. //----------------------------------------------------------------------------------//
  704. //    Perform the initialization necessary at start-up time.  Note that we use        //
  705. //    kCurrentProcess in our psn rather than calling GetCurrentProcess.  Using        //
  706. //    kCurrentProcess will allow us to record those events we send to ourselves,        //
  707. //    otherwise, the recorder won't recognize the psn and won't record our event!        //
  708. //----------------------------------------------------------------------------------//
  709. #pragma segment Initialize
  710. void Initialize()
  711. {
  712.     Handle                    menuBar;
  713.     long                    total, contig;
  714.     EventRecord             event;
  715.     short                    count;
  716.  
  717.     gInBackground = false;
  718.     InitGraf((Ptr)&qd.thePort);
  719.     InitWindows();
  720.     InitMenus();
  721.     InitDialogs(nil);
  722.     InitCursor();
  723.     InitAEHandlers();
  724.     for (count = 1; count <= 3; count++)
  725.         EventAvail(everyEvent, &event);
  726.      
  727.     SysEnvirons(kSysEnvironsVersion, &gMac);    
  728.     if (gMac.machineType < 0) 
  729.         SignalError(eWrongMachine);                // Less than 128K ROM's.
  730.     gHasWaitNextEvent = IsTrapAvailable(_WaitNextEvent, ToolTrap);
  731.      
  732.     if ((long)GetApplLimit() - (long)ApplicationZone() < kMinHeap) 
  733.         SignalError(eSmallSize);
  734.     
  735.     PurgeSpace(&total, &contig);
  736.     if (total < kMinSpace)
  737.         if (UnloadScrap() != noErr)
  738.             SignalError(eNoMemory);
  739.         else
  740.         {
  741.             PurgeSpace(&total, &contig);
  742.             if (total < kMinSpace)
  743.                 SignalError(eNoMemory);
  744.         }
  745.  
  746.     if (!(menuBar = GetNewMBar(rMenuBar)))        // Set up menu bar.
  747.         SignalError(eNoMemory);
  748.     SetMenuBar(menuBar);
  749.     DisposeHandle(menuBar);
  750.     AppendResMenu(GetMenuHandle(mApple), 'DRVR');            // Add DA's to menu.
  751.     DrawMenuBar();
  752.  
  753.         // Set up the self-addressed descriptor record.
  754.       gSelfPSN.highLongOfPSN = 0;
  755.       gSelfPSN.lowLongOfPSN = kCurrentProcess;        //* Use this instead of GetCurrentProcess *//
  756.       FailIfErr(AECreateDesc(typeProcessSerialNumber,(Ptr)&gSelfPSN,sizeof(ProcessSerialNumber),&gSelfAddress));
  757.     gNullDesc.descriptorType = typeNull;        // Initialize the global null descriptor record.
  758.     gNullDesc.dataHandle = nil;
  759.  
  760.     gRefNum = CurResFile();
  761.     gNumWindowsOpen = 0;
  762.     gNewWindows = 0;
  763. }
  764.  
  765. //----------------------------------------------------------------------------------//
  766. //    Returns true if the given trap number is implemented, else returns false.        //
  767. //----------------------------------------------------------------------------------//
  768. #pragma segment Initialize
  769. Boolean IsTrapAvailable(short trapNum, TrapType  tType)
  770. {
  771.     if ((tType == (unsigned char)ToolTrap) && (gMac.machineType > envMachUnknown) &&
  772.          (gMac.machineType < envMacII))
  773.     {                                            // it's a 512K, Plus, or SE
  774.         trapNum = trapNum & 0x03FF;
  775.         if (trapNum > 0x01FF)                    // which means the tool traps
  776.             trapNum = _Unimplemented;            // only go to 0x01FF
  777.     }
  778.     return(NGetTrapAddress(trapNum, tType) != GetToolTrapAddress(_Unimplemented));    // [pwpc]
  779. }
  780.  
  781. //----------------------------------------------------------------------------------//
  782. #pragma segment Initialize
  783. void SignalError(short error)
  784. {
  785.     AlertUser(error);
  786.     ExitToShell();
  787. }
  788.  
  789. //**********************************************************************************//
  790. //                    *  Apple Events and Object Model Support *                        //
  791. //**********************************************************************************//
  792.  
  793. //----------------------------------------------------------------------------------//
  794. //    Initializes all descriptor records passed in to this routine.  The variable        //
  795. //    argument list is null terminated.                                                //
  796. //----------------------------------------------------------------------------------//
  797. #pragma segment Main
  798. void MyInitDescs(AEDesc*  desc1, ... )            // Variable, null terminated argument list.
  799. {
  800.     va_list        argptr;                            // pointer to each argument in list.
  801.     AEDesc*        nextDesc;                        // next descriptor argument in list.
  802.  
  803.     va_start(argptr, desc1);
  804.     desc1->descriptorType = typeNull;
  805.     desc1->dataHandle = nil;
  806.     
  807.     while(nextDesc = va_arg(argptr, AEDesc *))
  808.     {
  809.         nextDesc->descriptorType = typeNull;
  810.         nextDesc->dataHandle = nil;
  811.     }
  812.     va_end(argptr);
  813. }
  814.     
  815. //----------------------------------------------------------------------------------//
  816. //    Dispose all descriptor records passed into this routine. (Variable arg. list).    //
  817. //----------------------------------------------------------------------------------//
  818. #pragma segment Main
  819. void MyDisposeDescs(AEDesc*  desc1, ... )        // Null terminated argument list.
  820. {
  821.     va_list        argptr;            // pointer to each argument in list.
  822.     AEDesc*        nextDesc;        // descriptor argument in list.
  823.  
  824.     va_start(argptr, desc1);
  825.     if (desc1->dataHandle)
  826.         AEDisposeDesc(desc1);
  827.  
  828.     while(nextDesc = va_arg(argptr, AEDesc *))
  829.     {
  830.         if (nextDesc->dataHandle)
  831.             AEDisposeDesc(nextDesc);
  832.     }
  833.     va_end(argptr);
  834. }
  835.  
  836. //----------------------------------------------------------------------------------//
  837. //    Converts a descriptor to a boolean.                                                //
  838. //----------------------------------------------------------------------------------//
  839. #pragma segment AppleEvents
  840. OSErr DescToBoolean(const AEDesc* desc, Boolean* boolvalue)
  841. {
  842.     AEDesc            tempDesc;
  843.     Handle            dataHandle;
  844.  
  845.     tempDesc.dataHandle = nil;
  846.     if (desc->descriptorType == typeBoolean)
  847.         dataHandle = desc->dataHandle;
  848.     else
  849.         if (AECoerceDesc(desc, typeBoolean, &tempDesc) == noErr)
  850.             dataHandle = tempDesc.dataHandle;
  851.         else
  852.             return(errAECoercionFail);
  853.     
  854.     *boolvalue = **dataHandle;
  855.     MyDisposeDescs(&tempDesc, kEndOfList);
  856.     return(noErr);
  857. }
  858.  
  859. //----------------------------------------------------------------------------------//
  860. //    Converts a descriptor to a long.                                                //
  861. //----------------------------------------------------------------------------------//
  862. #pragma segment AppleEvents
  863. OSErr DescToLong(const  AEDesc* desc, long* longvalue)
  864. {
  865.     AEDesc            tempDesc;
  866.     Handle            dataHandle;
  867.  
  868.     tempDesc.dataHandle = nil;
  869.     if (desc->descriptorType == typeLongInteger)
  870.         dataHandle = desc->dataHandle;
  871.     else
  872.         if (AECoerceDesc(desc, typeLongInteger, &tempDesc) == noErr)
  873.             dataHandle = tempDesc.dataHandle;
  874.         else
  875.             return(errAECoercionFail);
  876.     
  877.     *longvalue = *(LongPtr)*dataHandle;
  878.     MyDisposeDescs(&tempDesc, kEndOfList);
  879.     return(noErr);
  880. }
  881.  
  882. //----------------------------------------------------------------------------------//
  883. //    Converts a descriptor to a pascal string.                                        //
  884. //----------------------------------------------------------------------------------//
  885. #pragma segment AppleEvents
  886. OSErr DescToPString(const AEDesc* desc, Str255 str, short maxLength)
  887. {
  888.     AEDesc            tempDesc;
  889.     Handle            dataHandle;
  890.     long            charCount;
  891.  
  892.     tempDesc.dataHandle = nil;
  893.     if (desc->descriptorType == typeChar)
  894.         dataHandle = desc->dataHandle;
  895.     else
  896.         if (AECoerceDesc(desc, typeChar, &tempDesc) == noErr)
  897.             dataHandle = tempDesc.dataHandle;
  898.         else
  899.             return(errAECoercionFail);
  900.     
  901.     charCount = GetHandleSize(dataHandle);
  902.     if (charCount > maxLength)
  903.     {
  904.         MyDisposeDescs(&tempDesc, kEndOfList);
  905.         return(errAECoercionFail);
  906.     }
  907.  
  908.     str[0] = charCount;
  909.     HLock(dataHandle);
  910.     BlockMove(*dataHandle, &str[1], charCount);
  911.     HUnlock(dataHandle);        // This may be from desc, so must unlock.
  912.     MyDisposeDescs(&tempDesc, kEndOfList);
  913.     return(noErr);
  914. }
  915.  
  916. //----------------------------------------------------------------------------------//
  917. //    Create the first window in response to the Open Application Apple Event.        //
  918. //----------------------------------------------------------------------------------//
  919. #pragma segment Main
  920. pascal
  921. OSErr HandleOpenApp(AppleEvent *theAppleEvent, AppleEvent* reply, long refCon)
  922. {
  923.     #pragma unused (reply,refCon)
  924.     WindowPtr    window;
  925.     OSErr        err;
  926.     
  927.     if (!(err = GetMissingParams(theAppleEvent)))        // Error if any parameters.
  928.     {
  929.         if (window = DoCreateNewWindow((WindowPtr)-1))    // Create initial window
  930.             ShowWindow(window);
  931.         else
  932.             err = errAEEventNotHandled;
  933.     }
  934.     return(err);
  935. }
  936.  
  937. //----------------------------------------------------------------------------------//
  938. //    Send a Quit Application Apple Event to myself to terminate this app.            //
  939. //----------------------------------------------------------------------------------//
  940. #pragma segment Main
  941. void SendQuitApp()
  942. {
  943.     AppleEvent    myAppleEvent, reply;
  944.     
  945.         //    Create the Apple Event.
  946.     FailIfErr(AECreateAppleEvent(kCoreEventClass, kAEQuitApplication, &gSelfAddress,
  947.                                     kAutoGenerateReturnID, kAnyTransactionID, &myAppleEvent));
  948.         //    Send the Apple Event.
  949.       FailIfErr(AESend(&myAppleEvent, &reply, kAENoReply+kAENeverInteract, kAENormalPriority,
  950.                                 kAEDefaultTimeout, nil, nil));
  951.       AEDisposeDesc(&myAppleEvent);                // Dispose of the Apple Event.
  952. }
  953.  
  954. //----------------------------------------------------------------------------------//
  955. //    Quit the application.                                                            //
  956. //----------------------------------------------------------------------------------//
  957. #pragma segment Main
  958. pascal
  959. OSErr HandleQuitApp(AppleEvent* theAppleEvent, AppleEvent* reply, long refCon)
  960. {
  961.     #pragma unused (reply,refCon)
  962.     OSErr    err;
  963.     
  964.     if (!(err = GetMissingParams(theAppleEvent)))    // Error if there are any parameters.
  965.         Terminate();
  966.     return(err);
  967. }
  968.  
  969. //----------------------------------------------------------------------------------//
  970. //    This routine makes a clone of the given window by copying its bounds, zoom        //
  971. //    state, and title (with the addition of "copy") properties.                        //
  972. //----------------------------------------------------------------------------------//
  973. #pragma segment Main
  974. WindowPtr DoCloneWindow(WindowPtr windowToClone, WindowPtr behindWindow)
  975. {
  976.     WindowPtr    clonedWindow;
  977.     Rect        bounds;
  978.     Str255        title;
  979.  
  980.     if (clonedWindow = DoCreateNewWindow(behindWindow))
  981.     {
  982.         GetWTitle(windowToClone, title);
  983.         p2cstr(title);
  984.         strcat((char *)title, " copy\0");
  985.         c2pstr((char *)title);
  986.         bounds = DoGetWindowBounds(windowToClone);
  987.         SetWTitle(clonedWindow, title);
  988.         MoveWindow(clonedWindow, bounds.left, bounds.top, false);
  989.         SizeWindow(clonedWindow, bounds.right-bounds.left, bounds.bottom-bounds.top, true);
  990.         SetWRefCon(clonedWindow, GetWRefCon(windowToClone));
  991.         return(clonedWindow);
  992.     }
  993.     return(nil);
  994. }
  995.  
  996. //----------------------------------------------------------------------------------//
  997. //    Handle the Clone Apple Event and create a clone of the given object. To clone    //
  998. //    a window, I clone its bounds, zoom state, and visible properties. In addition,    //
  999. //    I clone the window's title and append " copy" to it for the cloned window's        //
  1000. //    title. If the insertion location parameter is not in the event record, I         //
  1001. //    perform the default behavior, which is to position the clone behind the         //
  1002. //    window being cloned.                                                            //
  1003. //----------------------------------------------------------------------------------//
  1004. #pragma segment Main
  1005. pascal
  1006. OSErr HandleClone(AppleEvent* theAppleEvent, AppleEvent* reply, long refCon)
  1007. {
  1008.     #pragma unused (refCon)
  1009.     AEDesc        cloneObject, windowObject, replyObject, insertionLoc;
  1010.     AERecord    insertionRec;
  1011.     DescType    theType, position;
  1012.     WindowPtr    windowToClone, window, rplcWindow, behindWindow = nil;
  1013.     Size        paramSize;
  1014.     OSErr        err = noErr;
  1015.  
  1016.  
  1017.     MyInitDescs(&cloneObject,&windowObject,&replyObject,&insertionLoc,&insertionRec,kEndOfList);
  1018.         //    Let's get the direct object, the object to clone.
  1019.     if (err = AEGetParamDesc(theAppleEvent, keyDirectObject, typeObjectSpecifier, &cloneObject))
  1020.         goto myExit;
  1021.     if (!(windowToClone = ResolveToWindow(&cloneObject)))
  1022.     {
  1023.         err = errAENoSuchObject;
  1024.         goto myExit;
  1025.     }
  1026.     else        // we have a window to clone.
  1027.     {
  1028.         if (!(err = AEGetParamDesc(theAppleEvent,keyAEInsertHere,typeInsertionLoc,&insertionLoc)))
  1029.             if (!(err = AECoerceDesc(&insertionLoc, typeAERecord, &insertionRec)))
  1030.                 // Get object as typeWildCard because it may be null or an object specifier.
  1031.                 if (!(err = AEGetKeyDesc(&insertionRec, keyAEObject, typeWildCard, &windowObject)))
  1032.                     if (!(err = AEGetKeyPtr(&insertionRec,keyAEPosition,typeEnumeration,&theType,
  1033.                                         (Ptr)&position,sizeof(DescType),¶mSize)))
  1034.                         err = FindRelativeWindow(&behindWindow, &windowObject, position, &rplcWindow);
  1035.  
  1036.         if (err)
  1037.             if (err == errAEDescNotFound)
  1038.                 behindWindow = windowToClone;        // Registry's default behavior.
  1039.             else
  1040.                 goto myExit;
  1041.     }
  1042.  
  1043.     if (window = DoCloneWindow(windowToClone, behindWindow))
  1044.     {
  1045.         if (((WindowPeek)windowToClone)->visible)
  1046.             ShowWindow(window);
  1047.         if (position == kAEReplace)
  1048.             CloseTheWindow(rplcWindow);
  1049.  
  1050.         if (reply->dataHandle != nil)
  1051.         {
  1052.             CreateWindowObjectSpec(window, kIndexKeyForm, &replyObject);
  1053.             err = AEPutParamDesc(reply, keyAEResult, &replyObject);
  1054.         }
  1055.     }
  1056.     else
  1057.         err = errAEEventNotHandled;
  1058.  
  1059. myExit:
  1060.     MyDisposeDescs(&cloneObject,&windowObject,&replyObject,&insertionLoc,&insertionRec,kEndOfList);
  1061.     return(err);
  1062. }    
  1063.  
  1064. //----------------------------------------------------------------------------------//
  1065. //    Send a Close Apple Event to myself to close the specified window.                //
  1066. //----------------------------------------------------------------------------------//
  1067. #pragma segment Main
  1068. void SendClose(WindowPtr  window)
  1069. {
  1070.     AppleEvent        myAppleEvent, reply;
  1071.     AEDesc            windowObject;                // The window object specifier.
  1072.  
  1073.                 //    Create the Close Apple Event.
  1074.     FailIfErr(AECreateAppleEvent(kAECoreSuite, kAEClose, &gSelfAddress, kAutoGenerateReturnID,
  1075.                                     kAnyTransactionID, &myAppleEvent));
  1076.                 //    Create the window object specifier and add this to myAppleEvent.
  1077.     CreateWindowObjectSpec(window, kIndexKeyForm, &windowObject);
  1078.     FailIfErr(AEPutParamDesc(&myAppleEvent, keyDirectObject, &windowObject));
  1079.                 //    Send the Apple Event.
  1080.       FailIfErr(AESend(&myAppleEvent, &reply, kAENoReply+kAECanInteract, kAENormalPriority,
  1081.                                 kAEDefaultTimeout, nil, nil));
  1082.                 //    Now dispose of the AppleEvent and object specifier.                                
  1083.       AEDisposeDesc(&myAppleEvent);
  1084.     AEDisposeDesc(&windowObject);
  1085. }
  1086.  
  1087. //----------------------------------------------------------------------------------//
  1088. //    Respond to the Close Apple Event by closing the specified window object.        //
  1089. //----------------------------------------------------------------------------------//
  1090. #pragma segment Main
  1091. pascal
  1092. OSErr HandleClose(AppleEvent* theAppleEvent, AppleEvent* reply, long refCon)
  1093. {
  1094.     #pragma unused (reply,refCon)
  1095.     AEDesc            windowObject;
  1096.     WindowPtr        windowToClose;
  1097.     OSErr            myErr;
  1098.     
  1099.     MyInitDescs(&windowObject,kEndOfList);
  1100.         //    First, get the direct object which is the object to close.
  1101.     myErr = AEGetParamDesc(theAppleEvent,keyDirectObject,typeObjectSpecifier,&windowObject);
  1102.     if (!myErr && !(myErr = GetMissingParams(theAppleEvent)))
  1103.     {
  1104.         if (windowToClose = ResolveToWindow(&windowObject))
  1105.             CloseTheWindow(windowToClose);
  1106.         else
  1107.             myErr = errAENoSuchObject;
  1108.     }
  1109.     MyDisposeDescs(&windowObject,kEndOfList);
  1110.     return(myErr);
  1111. }
  1112.  
  1113. //----------------------------------------------------------------------------------//
  1114. //    Respond to the Count Elements Apple Event.                                        //
  1115. //----------------------------------------------------------------------------------//
  1116. #pragma segment Main
  1117. pascal
  1118. OSErr HandleCountElements(AppleEvent* theAppleEvent, AppleEvent* reply, long refCon)
  1119. {
  1120.     #pragma unused (refCon)
  1121.     AEDesc            directObject;
  1122.     DescType        theType, theClass;
  1123.     Size            paramSize;
  1124.     OSErr            err;
  1125.     
  1126.  
  1127.     MyInitDescs(&directObject, kEndOfList);
  1128.         //    Get the direct object, should be null.
  1129.     if (!(err = AEGetParamDesc(theAppleEvent, keyDirectObject, typeWildCard, &directObject)))
  1130.         if (!(err = AEGetParamPtr(theAppleEvent,keyAEObjectClass,typeType,&theType,(Ptr)&theClass,
  1131.                     sizeof(DescType),¶mSize)))        // Get class of elements to count.
  1132.             err = GetMissingParams(theAppleEvent);        // Error if more parameters.
  1133.  
  1134.     if (err)
  1135.         goto myExit;
  1136.         
  1137.         //    If we had a deeper object hierarchy, we'd probably call AEResolve here, but...
  1138.         //    we only handle the window class contained within the null object.
  1139.     if (theClass == cWindow && directObject.descriptorType == typeNull)
  1140.         err = AEPutParamPtr(reply, keyAEResult, typeLongInteger, (Ptr)&gNumWindowsOpen, sizeof(long));
  1141.  
  1142. myExit:
  1143.     MyDisposeDescs(&directObject, kEndOfList);
  1144.     return(err);
  1145. }
  1146.  
  1147. //----------------------------------------------------------------------------------//
  1148. //    Send a Create Element Apple Event to myself to create a new window. By default, //
  1149. //    I am setting the position to the beginning of the null container (frontmost).    //
  1150. //    In this case, as well as at the end of the container, the object parameter is    //
  1151. //    the null container. If the position is before, after, or replace, the object    //
  1152. //    parameter must be an object specifier to indicate the relative window.            //
  1153. //----------------------------------------------------------------------------------//
  1154. #pragma segment Main
  1155. void SendCreateElement()
  1156. {
  1157.     AppleEvent        myAppleEvent, reply;
  1158.     AERecord        insertionRec;                    // Insertion Loc record.
  1159.     AEDesc            insertionLoc;                    // The coerced insertionRec.
  1160.     DescType        theType;
  1161.     
  1162.                 //    Create the Apple Event.
  1163.     FailIfErr(AECreateAppleEvent(kAECoreSuite, kAECreateElement, &gSelfAddress, kAutoGenerateReturnID,
  1164.                                     kAnyTransactionID, &myAppleEvent));
  1165.                 //    Attach the class of the new element, which in this case is cWindow.
  1166.     theType = cWindow;
  1167.       FailIfErr(AEPutParamPtr(&myAppleEvent, keyAEObjectClass, typeType, (Ptr)&theType, sizeof(DescType)));
  1168.  
  1169.                 //    Create insertion loc, object is null container and position is beginning.
  1170.     FailIfErr(AECreateList(nil, 0, true, &insertionRec));            // Create an AE Record.
  1171.     theType = kAEBeginning;
  1172.     FailIfErr(AEPutKeyDesc(&insertionRec, keyAEObject, &gNullDesc));
  1173.     FailIfErr(AEPutKeyPtr(&insertionRec, keyAEPosition, typeEnumeration, (Ptr)&theType, sizeof(DescType)));
  1174.     FailIfErr(AECoerceDesc(&insertionRec, typeInsertionLoc, &insertionLoc));
  1175.                 // Now add the insertion location descriptor record to the Apple Event.
  1176.     FailIfErr(AEPutParamDesc(&myAppleEvent, keyAEInsertHere, &insertionLoc));
  1177.                 //    Send the Apple Event.
  1178.       FailIfErr(AESend(&myAppleEvent, &reply, kAENoReply+kAECanInteract, kAENormalPriority,
  1179.                                 kAEDefaultTimeout, nil, nil));
  1180.                 //    Now dispose of the AppleEvent and other records.
  1181.       MyDisposeDescs(&myAppleEvent, &insertionRec, &insertionLoc, kEndOfList);
  1182. }
  1183.  
  1184. //----------------------------------------------------------------------------------//
  1185. //    Respond to the Create Element Apple event and create a new window. For this        //
  1186. //    application, the keyAEInsertHere parameter is optional. If this parameter is     //
  1187. //    not present, a new window is created in the frontmost position.                    //
  1188. //    This routine also handles the optional initial data parameters (keyAEData and    //
  1189. //    keyAEPropData) if they are present. A window object specifier must be in the    //
  1190. //    keyAEData parameter, which is essentially used to make a clone. If the            //
  1191. //    property data exists, these properties will override those previously set.        //
  1192. //----------------------------------------------------------------------------------//
  1193. #pragma segment Main
  1194. pascal
  1195. OSErr HandleCreateElement(AppleEvent* theAppleEvent, AppleEvent* reply, long refCon)
  1196. {
  1197.     #pragma unused (refCon)
  1198.     AEDesc            windowObject, dataObject, propData, propObject, replyObject;
  1199.     AEDesc            insLocParam;
  1200.     AERecord        insLocRec;
  1201.     AERecord        dataPropParam;                    // Initial data parameters.
  1202.     AEKeyword        keyWord;                        // Property id code for PropData.
  1203.     DescType        theType, theClass, position;
  1204.     WindowPtr        window, relativeWindow, dataWindow, rplcWindow;
  1205.     Rect            bounds;
  1206.     Size            theSize;
  1207.     Str255            buffer;
  1208.     long            numItems;
  1209.     short            i;
  1210.     Boolean            isVisible;
  1211.     OSErr            err;
  1212.     
  1213.     if (err = AEGetParamPtr(theAppleEvent, keyAEObjectClass, typeType, &theType, (Ptr)&theClass,
  1214.                     sizeof(DescType), &theSize))
  1215.         return(err);
  1216.     if (theClass != cWindow)            // We only handle elements of the class cWindow.
  1217.         return(errAEEventNotHandled);
  1218.     position = typeNull;
  1219.     MyInitDescs(&windowObject,&dataObject,&propData,&propObject,&insLocParam,&dataPropParam,&replyObject,&insLocRec,kEndOfList);
  1220.             // Now get the insertion location record as an AERecord, if it exists.
  1221.     if (!(err = AEGetParamDesc(theAppleEvent, keyAEInsertHere, typeInsertionLoc, &insLocParam)))
  1222.     {        // coerce the insertion loc record to an AE record.
  1223.         err = AECoerceDesc(&insLocParam, typeAERecord, &insLocRec);
  1224.             //    Get the object as typeWildCard because it may be a null descriptor or an object.
  1225.         if (!(err = AEGetKeyDesc(&insLocRec, keyAEObject, typeWildCard, &windowObject)))
  1226.             if (!(err = AEGetKeyPtr(&insLocRec, keyAEPosition, typeEnumeration, &theType, (Ptr)&position,
  1227.                         sizeof(DescType), &theSize)))
  1228.             {
  1229.                 relativeWindow = nil;
  1230.                 err = FindRelativeWindow(&relativeWindow, &windowObject, position, &rplcWindow);
  1231.             }
  1232.     }
  1233.     else
  1234.         if (err == errAEDescNotFound)    // No insertion loc, make it frontmost by default.
  1235.         {
  1236.             relativeWindow = (WindowPtr)-1;
  1237.             position = kAEBeginning;
  1238.             err = noErr;        // Not an error for me because I make this param optional.
  1239.         }
  1240.  
  1241.     if (err)
  1242.         goto myExit;
  1243.         
  1244.                 // Check if optional data parameter is present.
  1245.     if (!(err = AEGetParamDesc(theAppleEvent,keyAEData,typeObjectSpecifier,&dataObject)))
  1246.     {
  1247.         if (dataWindow = ResolveToWindow(&dataObject))
  1248.         {
  1249.             window = DoCloneWindow(dataWindow, relativeWindow);
  1250.             isVisible = ((WindowPeek)dataWindow)->visible;
  1251.         }
  1252.         else
  1253.         {
  1254.             err = errAENoSuchObject;
  1255.             goto myExit;
  1256.         }
  1257.     }
  1258.     else
  1259.         if (err == errAEDescNotFound)    // The optional data parameter is not present.
  1260.         {
  1261.             if (window = DoCreateNewWindow(relativeWindow))
  1262.             {
  1263.             err = noErr;
  1264.             isVisible = true;
  1265.                 if (position == kAEReplace)            // Replace the window in the right position.
  1266.                 {
  1267.                     bounds = DoGetWindowBounds(rplcWindow);
  1268.                     MoveWindow(window, bounds.left, bounds.top, false);
  1269.                 }
  1270.             }
  1271.             else
  1272.             {
  1273.                 err = errAEEventNotHandled;        // couldn't create a new window.
  1274.                 goto myExit;
  1275.             }
  1276.         }
  1277.         else
  1278.             goto myExit;
  1279.  
  1280.     if (isVisible)                    // We set the visibility here because it may be changed
  1281.         ShowWindow(window);            // by the following property data.
  1282.  
  1283.             // Handle PropData parameter if it exists.        
  1284.     if (!(err = AEGetParamDesc(theAppleEvent,keyAEPropData,typeAERecord,&dataPropParam)))
  1285.     {
  1286.         AECountItems(&dataPropParam, &numItems);
  1287.         for (i = 1; i <= numItems; i++)
  1288.         {
  1289.             if (!(err = AEGetNthPtr(&dataPropParam,i,typeWildCard,&keyWord,&theType,&buffer,sizeof(Str255),&theSize)))
  1290.             {
  1291.                 AECreateDesc(keyWord, (Ptr)&window, sizeof(Ptr), &propObject);
  1292.                 AECreateDesc(theType, (Ptr)&buffer, theSize, &propData);
  1293.                 err = DoSetData(&propObject, &propData);
  1294.                 AEDisposeDesc(&propObject);
  1295.                 AEDisposeDesc(&propData);
  1296.                 if (err)
  1297.                     break;
  1298.             }
  1299.         }
  1300.     }
  1301.     
  1302.     if (!err || err == errAEDescNotFound)
  1303.     {
  1304.         if (position == kAEReplace)
  1305.             CloseTheWindow(rplcWindow);
  1306.         err = noErr;
  1307.         if (reply->dataHandle != nil)
  1308.         {
  1309.             CreateWindowObjectSpec(window, kIndexKeyForm, &replyObject);
  1310.             err = AEPutParamDesc(reply, keyAEResult, &replyObject);
  1311.         }
  1312.     }
  1313.         
  1314. myExit:
  1315.     MyDisposeDescs(&windowObject,&dataObject,&propData,&propObject,&insLocParam,&dataPropParam,&replyObject,&insLocRec,kEndOfList);
  1316.     return(err);
  1317. }
  1318.  
  1319. //----------------------------------------------------------------------------------//
  1320. //    Respond to the Do Objects Exist AE by attempting to resolve the object specifier//
  1321. //----------------------------------------------------------------------------------//
  1322. #pragma segment Main
  1323. pascal
  1324. OSErr HandleDoObjectsExist(AppleEvent* theAppleEvent, AppleEvent* reply, long refCon)
  1325. {
  1326.     #pragma unused (reply,refCon)
  1327.     AEDesc        target, token;
  1328.     Boolean        exists;
  1329.     OSErr        err;
  1330.     
  1331.     MyInitDescs(&target, &token, kEndOfList);
  1332.     if (!(err = AEGetParamDesc(theAppleEvent, keyDirectObject, typeWildCard, &target)))
  1333.         if (!(err = GetMissingParams(theAppleEvent)))            // Check for missing params.
  1334.         {
  1335.             exists = true;
  1336.             token.descriptorType = typeNull;
  1337.             if (target.descriptorType != typeNull)
  1338.                 exists = (AEResolve(&target, kAEIDoMinimum, &token) == noErr);
  1339.  
  1340.                 //    Add data to the reply Apple event record.
  1341.               err = AEPutParamPtr(reply, keyDirectObject,typeBoolean,(Ptr)&exists,sizeof(Boolean));
  1342.         }
  1343. myExit:
  1344.     MyDisposeDescs(&target, &token, kEndOfList);
  1345.     return(err);
  1346. }
  1347.  
  1348. //----------------------------------------------------------------------------------//
  1349. //    Send the Set Data Apple Event with the object, property, and property data.        //
  1350. //    *NOTE*: I am sending myself the Set Data event in response to user interaction.    //
  1351. //    These actions have already occurred by this time, so I am sending the event        //
  1352. //    with the "don't execute" flag set for "smart" recorders.  A "smart" recorder    //
  1353. //    would check this flag when it intercepts the Apple event, and if it was set,    //
  1354. //    it wouldn't pass the event to the application.                                    //
  1355. //----------------------------------------------------------------------------------//
  1356. #pragma segment Main
  1357. void SendSetData( AEDesc*    propDesc,            // the property to set
  1358.                   AEDesc*    propData,            // the property data
  1359.                   AEDesc*    target  )        // object to set property of
  1360. {
  1361.     AppleEvent    myAppleEvent, reply;
  1362.     AEDesc        objectToSet;
  1363.  
  1364.     FailIfErr(AECreateAppleEvent(kAECoreSuite, kAESetData, &gSelfAddress, kAutoGenerateReturnID,
  1365.                                     kAnyTransactionID, &myAppleEvent));
  1366.                 //  Create the object specifier for the property of the object.
  1367.     FailIfErr(CreateObjSpecifier(cProperty, target, formPropertyID, propDesc, 
  1368.                                         false, &objectToSet));
  1369.                 //    Attach the property object specifier.
  1370.     FailIfErr(AEPutParamDesc(&myAppleEvent, keyDirectObject, &objectToSet));
  1371.                 //    Add the property data.
  1372.     FailIfErr(AEPutParamDesc(&myAppleEvent, keyAEData, propData));
  1373.       FailIfErr(AESend(&myAppleEvent, &reply, kAENoReply+kAECanInteract+kAEDontExecute, kAENormalPriority,
  1374.                                 kAEDefaultTimeout, nil, nil));
  1375.  
  1376.     AEDisposeDesc(&objectToSet);                    // Clean up.                                
  1377.     AEDisposeDesc(&myAppleEvent);
  1378. }
  1379.  
  1380. //----------------------------------------------------------------------------------//
  1381. //    To set the data of an object, the expected data is passed in its raw form with    //
  1382. //    the property type in the descriptorType field and the data in the dataHandle.    //
  1383. //----------------------------------------------------------------------------------//
  1384. #pragma segment Main
  1385. pascal
  1386. OSErr HandleSetData(AppleEvent* theAppleEvent, AppleEvent* reply, long refCon)
  1387. {
  1388.     #pragma unused (reply,refCon)
  1389.     AEDesc        target, data, token;
  1390.     OSErr        err;
  1391.     
  1392.     MyInitDescs(&target, &data,&token, kEndOfList);
  1393.         //    First, get the direct object. This is the object whose data is to be set.
  1394.     if (!(err = AEGetParamDesc(theAppleEvent, keyDirectObject, typeObjectSpecifier, &target)))
  1395.         if (!(err = AEResolve(&target, kAEIDoMinimum, &token)))        // Resolve it.
  1396.            if (!(err = AEGetParamDesc(theAppleEvent, keyAEData, typeWildCard, &data)))
  1397.               err = DoSetData(&token, &data);
  1398.     MyDisposeDescs(&target, &data, &token, kEndOfList);
  1399.     return(err);
  1400. }
  1401.  
  1402. //----------------------------------------------------------------------------------//
  1403. //    Return a reply to the Get Data or Get Data Size Apple Event for the requested    //
  1404. //    data. The refcon parameter is used to distinguish the two events. If typeBest    //
  1405. //    is the requested return type, the data's descriptor type is the result type.    //
  1406. //    **NOTE: Do not use the same descriptor as source and dest in AECoerceDesc().    //
  1407. //    This routine creates a copy of the source, and then it is impossible to dispose    //
  1408. //    of the memory originally contained in the source's dataHandle.                    //
  1409. //    2/25/92 - Removed FailIfErr calls. Now the error is returned as a result.        //
  1410. //----------------------------------------------------------------------------------//
  1411. #pragma segment Main
  1412. pascal
  1413. OSErr HandleGetData( AppleEvent*    theAppleEvent,
  1414.                      AppleEvent*    reply,
  1415.                      long            refCon    )        // kAEGetData or kAEGetDataSize.
  1416. {
  1417.     AEDesc            theObject, token;                // direct object and resolved token.
  1418.     AEDesc            objectData, tempDesc;            // object data, and coerced data.
  1419.     DescType        reqType;
  1420.     WindowPtr        window;
  1421.     Size            theSize;
  1422.     OSErr            err;
  1423.     
  1424.     MyInitDescs(&theObject, &objectData, &token, kEndOfList);
  1425.             //    First, get the direct objet.
  1426.     if (err = AEGetParamDesc(theAppleEvent, keyDirectObject, typeObjectSpecifier, &theObject))
  1427.         goto myExit;
  1428.             //    Next, get the requested return type, if it exists.
  1429.     if (err = AEGetParamPtr(theAppleEvent, keyAERequestedType, typeType, &reqType,
  1430.                                 (Ptr)&reqType, sizeof(DescType), &theSize))
  1431.     {
  1432.         if (err == errAEDescNotFound)        // not an error if return type is not found
  1433.         {
  1434.             err = noErr;
  1435.             reqType = typeWildCard;
  1436.         }
  1437.         else
  1438.             goto myExit;
  1439.     }
  1440.     if (err = GetMissingParams(theAppleEvent))            // check for missing params
  1441.         goto myExit;
  1442.  
  1443.             //    Resolve the object specifier and get the token containing the property and container.
  1444.     if (!(err = AEResolve(&theObject, kAEIDoMinimum, &token)))
  1445.         if (window = (WindowPtr)*(LongPtr)*token.dataHandle)        // Nil for application; WindowPtr for window
  1446.             err = GetWindowData(token.descriptorType, window, &objectData);
  1447.         else
  1448.             err = GetAppData(token.descriptorType, &objectData);
  1449.  
  1450.     if (err == noErr && reply->dataHandle != nil)
  1451.     {        //    Add data to the reply Apple event record.
  1452.         if (reqType != typeWildCard && reqType != typeBest &&
  1453.             reqType != objectData.descriptorType)
  1454.         {
  1455.             err = AECoerceDesc(&objectData, reqType, &tempDesc);
  1456.             MyDisposeDescs(&objectData, kEndOfList);
  1457.             objectData.descriptorType = tempDesc.descriptorType;
  1458.             objectData.dataHandle = tempDesc.dataHandle;
  1459.         }
  1460.         if (!err)
  1461.         {
  1462.             if (refCon == kAEGetData)                // return data
  1463.                 err = AEPutParamDesc(reply, keyAEResult, &objectData);
  1464.             else if (refCon == kAEGetDataSize)        // return data size
  1465.             {
  1466.                 theSize = GetHandleSize(objectData.dataHandle);
  1467.                   err = AEPutParamPtr(reply, keyAEResult, typeLongInteger, (Ptr)&theSize, sizeof(long));
  1468.             }
  1469.         }
  1470.     }
  1471.     
  1472. myExit:
  1473.     MyDisposeDescs(&theObject, &objectData, &token, kEndOfList);
  1474.     return(err);
  1475. }
  1476.  
  1477. //----------------------------------------------------------------------------------//
  1478. //    Send a Move Apple event to myself in response to a user selecting a window        //
  1479. //    and making it frontmost. This event is sent with the insertion location record    //
  1480. //    specifying the beginning of the null container. If the index is non-zero, this    //
  1481. //    indicates that the move event has already been performed by DragWindow(). Thus,    //
  1482. //    this event is passed with the don't execute flag set.                            //
  1483. //----------------------------------------------------------------------------------//
  1484. #pragma segment Main
  1485. void SendMoveEvent(WindowPtr windowToMove, long index)
  1486. {
  1487.     AppleEvent        myAppleEvent, reply, windowObject;
  1488.     AERecord        insertionRec;                    // Insertion Loc record.
  1489.     AEDesc            insertionLoc;                    // The coerced insertionRec.
  1490.     DescType        theType;
  1491.     
  1492.         //    Create the Apple Event.
  1493.     FailIfErr(AECreateAppleEvent(kAECoreSuite, kAEMove, &gSelfAddress, kAutoGenerateReturnID,
  1494.                                     kAnyTransactionID, &myAppleEvent));
  1495.         //    Create the object spec for the window to move.
  1496.     FailIfErr(CreateWindowObjectSpec(windowToMove, kIndexKeyForm, &windowObject));
  1497.     FailIfErr(AEPutParamDesc(&myAppleEvent, keyDirectObject, &windowObject));
  1498.  
  1499.         //    Create insertion loc record for beginning of null container.
  1500.     FailIfErr(AECreateList(nil, 0, true, &insertionRec));            // Create an AE Record.
  1501.     theType = kAEBeginning;
  1502.     FailIfErr(AEPutKeyDesc(&insertionRec, keyAEObject, &gNullDesc));
  1503.     FailIfErr(AEPutKeyPtr(&insertionRec,keyAEPosition,typeEnumeration,(Ptr)&theType,sizeof(DescType)));
  1504.     FailIfErr(AECoerceDesc(&insertionRec, typeInsertionLoc, &insertionLoc));
  1505.         // Now add the insertion location descriptor record to the Apple Event.
  1506.     FailIfErr(AEPutParamDesc(&myAppleEvent, keyAEInsertHere, &insertionLoc));
  1507.         //    Send the Apple Event.
  1508.     if (index)
  1509.           FailIfErr(AESend(&myAppleEvent, &reply, kAENoReply+kAECanInteract+kAEDontExecute,
  1510.                             kAENormalPriority, kAEDefaultTimeout, nil, nil));
  1511.     else
  1512.           FailIfErr(AESend(&myAppleEvent, &reply, kAENoReply+kAECanInteract,
  1513.                             kAENormalPriority, kAEDefaultTimeout, nil, nil));
  1514.  
  1515.         //    Now dispose of the AppleEvent and other records.
  1516.     MyDisposeDescs(&myAppleEvent,&windowObject,&insertionRec,&insertionLoc,kEndOfList);
  1517. }
  1518.  
  1519. //----------------------------------------------------------------------------------//
  1520. //    Respond to the Move Apple Event by reordering the window list.  For CoreSample,    //
  1521. //    the keyAEInsertHere parameter is optional. If this parameter does not exist,    //
  1522. //    the specified window will move the  to the front.                                //
  1523. //----------------------------------------------------------------------------------//
  1524. #pragma segment Main
  1525. pascal
  1526. OSErr HandleMove(AppleEvent* theAppleEvent, AppleEvent* reply, long refCon)
  1527. {
  1528.     #pragma unused (refCon)
  1529.     AEDesc            object, windowObj, replyObj, insertionLoc;
  1530.     AERecord        insertionRec;
  1531.     DescType        theType, position;
  1532.     WindowPtr        windowToMove, relativeWindow, rplcWindow;
  1533.     Rect            bounds;
  1534.     Size            paramSize;
  1535.     OSErr            err;
  1536.     
  1537.     MyInitDescs(&object,&windowObj,&insertionLoc,&insertionRec,&replyObj,kEndOfList);
  1538.         //    First, get the direct parameter, the object to move.
  1539.     if (err = AEGetParamDesc(theAppleEvent, keyDirectObject, typeObjectSpecifier, &object))
  1540.         goto myExit;
  1541.     if (!(windowToMove = ResolveToWindow(&object)))            // Check if valid window object.
  1542.     {
  1543.         err = errAENoSuchObject;
  1544.         goto myExit;
  1545.     }
  1546.  
  1547.         // Retrieve the insertion location record, if it exists.
  1548.     if ((err = AEGetParamDesc(theAppleEvent,keyAEInsertHere,typeInsertionLoc,&insertionLoc)) == errAEDescNotFound)
  1549.     {            // Execute *MY* default behavior since insertion loc param not present.
  1550.         SelectWindow(windowToMove);
  1551.         err = noErr;
  1552.         goto myExit;
  1553.     }
  1554.     else
  1555.         if (err)
  1556.             goto myExit;
  1557.         else            // get data from insertion loc and coerce it to typeAERecord.
  1558.         {
  1559.             if ((err = GetMissingParams(theAppleEvent))  ||
  1560.                 (err = AECoerceDesc(&insertionLoc, typeAERecord, &insertionRec)) || 
  1561.                 (err = AEGetKeyDesc(&insertionRec,keyAEObject,typeWildCard,&windowObj)) ||
  1562.                 (err = AEGetKeyPtr(&insertionRec,keyAEPosition,typeEnumeration,&theType,
  1563.                                     (Ptr)&position,sizeof(DescType),¶mSize)))
  1564.                     goto myExit;
  1565.         }
  1566.  
  1567.     if (!(err = FindRelativeWindow(&relativeWindow,&windowObj,position,&rplcWindow)))
  1568.     {
  1569.         if (position == kAEReplace)
  1570.             if (windowToMove == rplcWindow)
  1571.                 goto myExit;                // do nothing.
  1572.             else
  1573.             {
  1574.                 bounds = DoGetWindowBounds(rplcWindow);
  1575.                 CloseTheWindow(rplcWindow);
  1576.                 MoveWindow(windowToMove, bounds.left, bounds.top, false);
  1577.             }
  1578.  
  1579.         if (relativeWindow == (WindowPtr)-1)        // [pwpc]
  1580.             SelectWindow(windowToMove);
  1581.         else
  1582.             if (windowToMove != relativeWindow)
  1583.                 SendBehind(windowToMove, relativeWindow);        // NOTE: may have to call PaintOne and
  1584.                                                                 // CalcVis if after; see IM I-286
  1585.         if (position == kAEReplace && windowToMove != rplcWindow)
  1586.         {
  1587.             bounds = DoGetWindowBounds(rplcWindow);
  1588.             CloseTheWindow(rplcWindow);
  1589.             MoveWindow(windowToMove, bounds.left, bounds.top, false);
  1590.         }
  1591.     }
  1592.  
  1593. myExit:
  1594.     if (!err)
  1595.         if (reply->dataHandle != nil)
  1596.         {
  1597.             CreateWindowObjectSpec(windowToMove, kIndexKeyForm, &replyObj);
  1598.             err = AEPutParamDesc(reply, keyAEResult, &replyObj);
  1599.         }
  1600.     MyDisposeDescs(&object,&windowObj,&insertionLoc,&insertionRec,&replyObj,kEndOfList);
  1601.     return(err);
  1602. }
  1603.  
  1604. //----------------------------------------------------------------------------------//
  1605. //    Set up the descriptor records needed to set the data for the bounds, position,    //
  1606. //    and zoomed properties.  The bounds is set in response to sizing a window; the    //
  1607. //    position is set after dragging a window; and the isZoomed property is set when    //
  1608. //    zooming a window in or out.                                                        //
  1609. //----------------------------------------------------------------------------------//
  1610. #pragma segment Main
  1611. void SetUpPropertyData( WindowPtr        window,            // Window object.
  1612.                         DescType        propType,        // Property descriptor type.
  1613.                         DescType        dataType,        // Descriptor type for data.
  1614.                         Size            dataSize   )    // Size of data.
  1615. {
  1616.     AEDesc        windowObject, theData, theProperty;
  1617.     Rect        bounds;
  1618.     Boolean        isZoomed;
  1619.     
  1620.     MyInitDescs(&windowObject, &theData, &theProperty, kEndOfList);
  1621.     if (propType == pIsZoomed)
  1622.     {
  1623.         isZoomed = (Boolean)GetWRefCon(window);
  1624.         FailIfErr(AECreateDesc(dataType,(Ptr)&isZoomed,dataSize,&theData));
  1625.     }
  1626.     else        // it's either pBounds or pPosition.
  1627.     {
  1628.           bounds = DoGetWindowBounds(window);
  1629.         FailIfErr(AECreateDesc(dataType, (Ptr)&bounds, dataSize, &theData));
  1630.     }
  1631.         
  1632.     CreateWindowObjectSpec(window, kIndexKeyForm, &windowObject);
  1633.     FailIfErr(AECreateDesc(typeType, (Ptr)&propType, sizeof(DescType), &theProperty));
  1634.  
  1635.     SendSetData(&theProperty, &theData, &windowObject);
  1636.     MyDisposeDescs(&windowObject, &theData, &theProperty, kEndOfList);
  1637. }
  1638.  
  1639. //----------------------------------------------------------------------------------//
  1640. //    Set the property data for the specified object.  For now, we only handle window    //
  1641. //    objects, and you may only set the modifiable properties (defined in Registry).    //
  1642. //    *NOTE*:  We do not allow the application's properties to be modified.            //
  1643. //----------------------------------------------------------------------------------//
  1644. #pragma segment Main
  1645. OSErr DoSetData( AEDesc*    token,                // Contains the property and object.
  1646.                  AEDesc*    data    )            // Contains the data to set.
  1647. {
  1648.     AEDesc            propData;            // Property data.
  1649.     Rect            bounds;
  1650.     GrafPtr            oldPort;
  1651.     WindowPtr        window, behindWindow;
  1652.     Str255            name;
  1653.     long            newIndex;
  1654.     short            part;
  1655.     Boolean            value;
  1656.     Point            pt;
  1657.     OSErr            err;
  1658.  
  1659.     err = noErr;
  1660.     if (window = (WindowPtr)*(LongPtr)*(token->dataHandle))
  1661.     {
  1662.         GetPort(&oldPort);
  1663.         switch (token->descriptorType)
  1664.         {
  1665.             case pBounds:
  1666.                 if (data->descriptorType != typeQDRectangle)
  1667.                 {
  1668.                     propData.dataHandle = nil;
  1669.                     err = AECoerceDesc(data, typeQDRectangle, &propData);
  1670.                     bounds = *(Rect *)*propData.dataHandle;        // Get content region.
  1671.                     MyDisposeDescs(&propData, kEndOfList);
  1672.                 }
  1673.                 else
  1674.                     bounds = *(Rect *)*data->dataHandle;        // Get content region.
  1675.         
  1676.                 if (!err)
  1677.                 {
  1678.                     SetPort(window);
  1679.                     InvalRect(&window->portRect);
  1680.         
  1681.                         // Real applications may want to make a sanity check on the new bounds.        
  1682.                     MoveWindow(window, bounds.left, bounds.top, false);
  1683.                      SizeWindow(window, bounds.right-bounds.left, bounds.bottom-bounds.top, true);
  1684.                     InvalRect(&window->portRect);
  1685.                 }
  1686.                 break;
  1687.             
  1688.             case pIndex:
  1689.                 if (DescToLong(data,&newIndex) != noErr)
  1690.                     return(errAECoercionFail);        // Data cannot be coerced.
  1691.  
  1692.                 if (newIndex > gNumWindowsOpen)
  1693.                     err = errAEIndexTooLarge;
  1694.                 else
  1695.                 {
  1696.                     if (newIndex == 1)
  1697.                         SelectWindow(window);
  1698.                     else
  1699.                         if (behindWindow = GetWindowAtIndex(newIndex))
  1700.                             SendBehind(window, behindWindow);
  1701.                         else
  1702.                             err = errAEEventFailed;
  1703.                 }
  1704.                 break;
  1705.                 
  1706.             case pIsZoomed:
  1707.                 if (DescToBoolean(data,&value) != noErr)
  1708.                     return(errAECoercionFail);            // Data cannot be coerced.
  1709.                     
  1710.                 part = value ? inZoomOut : inZoomIn;
  1711.                 ZoomIt(window, part);
  1712.                 break;
  1713.  
  1714.             case pName:
  1715.                 if (DescToPString(data,name,kMaxStrSize) != noErr)
  1716.                     return(errAECoercionFail);
  1717.                 SetWTitle(window, name);
  1718.                 break;
  1719.             
  1720.             case pPosition:
  1721.                 if (data->descriptorType != typeQDPoint)
  1722.                 {
  1723.                     propData.dataHandle = nil;
  1724.                     err = AECoerceDesc(data, typeQDPoint, &propData);
  1725.                     pt = *(Point *)*propData.dataHandle;
  1726.                     MyDisposeDescs(&propData, kEndOfList);
  1727.                 }
  1728.                 else
  1729.                     pt = *(Point *)*data->dataHandle;
  1730.  
  1731.                 if (!err)
  1732.                 {
  1733.                         // Real applications may want to make a sanity check on the new loc.
  1734.                     SetPort(window);
  1735.                     MoveWindow(window, pt.h, pt.v, false);
  1736.                     InvalRect(&window->portRect);
  1737.                 }
  1738.                 break;
  1739.             
  1740.             case pVisible:
  1741.                 if (DescToBoolean(data,&value) != noErr)
  1742.                     return(errAECoercionFail);        // Data cannot be coerced.
  1743.                 if (value)
  1744.                     ShowWindow(window);
  1745.                 else
  1746.                     HideWindow(window);
  1747.                 break;
  1748.                 
  1749.             default:                        // No other properties are modifiable.
  1750.                 return(errAENotModifiable);
  1751.         }
  1752.         SetPort(oldPort);
  1753.     }
  1754.     else
  1755.         return(errAEEventFailed);
  1756.     return(err);
  1757. }
  1758.  
  1759. //----------------------------------------------------------------------------------//
  1760. //    This is a dummy handler that receives Apple events which I don't handle.  It     //
  1761. //    is mainly provided as a stub in order to support all the events in the             //
  1762. //    required suite, as well as the entire core suite.  This is the handler for the    //
  1763. //    Open Document and Print Document events (required suite); and the Save, Get     //
  1764. //    Class Info,    and Get Event Info events (core suite).  The Get Class Info and Get    //
  1765. //    Event Info events "MAY" be supported internally in the future, so applications    //
  1766. //    will not need to handle these events themselves.  This support may be provided    //
  1767. //    since it would be consistent across all applications, and the information may    //
  1768. //    be retrieved from the 'aeut'/'aete' resources.                                    //
  1769. //----------------------------------------------------------------------------------//
  1770. #pragma segment Main
  1771. pascal
  1772. OSErr DummyHandler( AppleEvent        *theAppleEvent,
  1773.                     AppleEvent        *reply,
  1774.                     long            refCon    )
  1775. {
  1776.     #pragma unused (theAppleEvent,reply,refCon)
  1777.     return(errAEEventNotHandled);
  1778. }
  1779.  
  1780. //----------------------------------------------------------------------------------//
  1781. //    Locate the window that is relative to the specified window object at the        //
  1782. //    insertion position.  If the location is replace, the window to replace is         //
  1783. //    closed, and its bounds are returned to the calling routine.                        //
  1784. //    **Note**: if windowObj is used within this routine, the object param will        //
  1785. //    contain the same dataHandle. This will be disposed of by the calling routine.    //
  1786. //----------------------------------------------------------------------------------//
  1787. #pragma segment Main
  1788. OSErr FindRelativeWindow( WindowPtr*    relativeWindow,    // window before insertion loc.
  1789.                           AEDesc*        object,            // object to be relative to.
  1790.                           DescType        position,            // insertion position.
  1791.                           WindowPtr*    replaceWindow )    // window to replace.
  1792. {
  1793.     AEDesc        windowObj;                    // Coerced descriptor.
  1794.     WindowPtr    windowToReplace;
  1795.     long        index;
  1796.     OSErr        err;
  1797.     
  1798.     err = noErr;
  1799.     *replaceWindow = nil;
  1800.     switch(position)
  1801.     {
  1802.         case kAEBeginning:                        // The object should be the container.
  1803.             if (object->descriptorType == typeNull)
  1804.                 *relativeWindow = (WindowPtr)-1;
  1805.             else
  1806.                 err = errAENoSuchObject;
  1807.             break;
  1808.         
  1809.         case kAEEnd:                            // The object should be the container.
  1810.             if (object->descriptorType == typeNull)
  1811.                 *relativeWindow = nil;
  1812.             else
  1813.                 err = errAENoSuchObject;
  1814.             break;
  1815.             
  1816.         case kAEBefore:                            // The object should be an object specifier.
  1817.         case kAEReplace:
  1818.             if (object->descriptorType != typeObjectSpecifier)
  1819.             {
  1820.                 err = AECoerceDesc(object, typeObjectSpecifier, &windowObj);
  1821.                 MyDisposeDescs(object, kEndOfList);
  1822.                 object->descriptorType = windowObj.descriptorType;
  1823.                 object->dataHandle = windowObj.dataHandle;
  1824.             }
  1825.             
  1826.             if (!err)
  1827.                 if (windowToReplace = ResolveToWindow(object))
  1828.                 {
  1829.                     index = GetWindowIndexNum(windowToReplace);
  1830.                     *relativeWindow = (index==1) ? (WindowPtr)-1 : GetWindowAtIndex(index-1);
  1831.                     if (position == kAEReplace)
  1832.                         *replaceWindow = windowToReplace;
  1833.             }
  1834.             else            // We weren't able to resolve the object specifier to a window.
  1835.                 err = errAENoSuchObject;
  1836.             break;
  1837.             
  1838.         case kAEAfter:                        // The object should be an object specifier.
  1839.             if (object->descriptorType != typeObjectSpecifier)
  1840.             {
  1841.                 err = AECoerceDesc(object,typeObjectSpecifier,&windowObj);
  1842.                 MyDisposeDescs(object, kEndOfList);
  1843.                 object->descriptorType = windowObj.descriptorType;
  1844.                 object->dataHandle = windowObj.dataHandle;
  1845.             }
  1846.  
  1847.             if (!err)
  1848.                 if (!(*relativeWindow = ResolveToWindow(object)))
  1849.                     err = errAENoSuchObject;
  1850.             break;
  1851.             
  1852.         default:
  1853.             return(errAEEventNotHandled);
  1854.     }
  1855.     return(err);
  1856. }
  1857.  
  1858. //----------------------------------------------------------------------------------//
  1859. //    Retrieves the data for the specified property of the window.  The result token    //
  1860. //    contains the type of the data in the descriptorType field, and the data itself    //
  1861. //    in the dataHandle field.  I know my application's window properties             //
  1862. //    (i.e., has title bar, has close box, is zoomable, etc.), so I set up the         //
  1863. //    result token accordingly.  If your application handles various window types,    //
  1864. //    you may need to look at the window defproc to determine which type of window it    //
  1865. //    is.  If the property is pBestType or pDefaultType, I return an object specifier//
  1866. //    for the window which may be used to easily reference it.                        //
  1867. //----------------------------------------------------------------------------------//
  1868. #pragma segment Main
  1869. OSErr GetWindowData( DescType        theProperty,        // Window property.
  1870.                      WindowPtr        window,
  1871.                      AEDesc            *result    )            // Contains the result upon return.
  1872. {
  1873.     DescType        theType;
  1874.     Str255            title;
  1875.     Rect            bounds;
  1876.     long            index;
  1877.     Boolean            myAnswer;
  1878.  
  1879.     switch (theProperty)
  1880.     {
  1881.         case pBestType:
  1882.         case pDefaultType:
  1883.             return(CreateWindowObjectSpec(window, kIndexKeyForm, result));
  1884.  
  1885.         case pBounds:
  1886.               bounds = DoGetWindowBounds(window);
  1887.             return(AECreateDesc(typeQDRectangle, (Ptr)&bounds, sizeof(Rect), result));
  1888.             
  1889.         case pClass:
  1890.             theType = cWindow;
  1891.             return(AECreateDesc(typeType, (Ptr)&theType, sizeof(DescType), result));
  1892.  
  1893.         case pIndex:
  1894.             index = GetWindowIndexNum(window);
  1895.             return(AECreateDesc(typeLongInteger, (Ptr)&index, sizeof(long), result));
  1896.                 
  1897.         case pName:
  1898.             GetWTitle(window, title);
  1899.             return(AECreateDesc(typeChar, (Ptr)&title[1], title[0], result));
  1900.  
  1901.         case pPosition:
  1902.               bounds = DoGetWindowBounds(window);
  1903.             return(AECreateDesc(typeQDPoint, (Ptr)&bounds, sizeof(Point), result));
  1904.  
  1905.         case pHasCloseBox:
  1906.         case pHasTitleBar:
  1907.         case pIsResizable:
  1908.         case pIsZoomable:
  1909.             myAnswer = true;
  1910.             return(AECreateDesc(typeBoolean, (Ptr)&myAnswer, sizeof(Boolean), result));
  1911.  
  1912.         case pIsFloating:
  1913.         case pIsModal:
  1914.             myAnswer = false;
  1915.             return(AECreateDesc(typeBoolean, (Ptr)&myAnswer, sizeof(Boolean), result));
  1916.             
  1917.         case pIsZoomed:
  1918.             myAnswer = GetWRefCon(window);
  1919.             return(AECreateDesc(typeBoolean, (Ptr)&myAnswer, sizeof(Boolean), result));
  1920.         
  1921.         case pVisible:                    // Must check this because it is modifiable.
  1922.             myAnswer = ((WindowPeek)window)->visible;
  1923.             return(AECreateDesc(typeBoolean, (Ptr)&myAnswer, sizeof(Boolean), result));
  1924.  
  1925.         case pSelection:                // No selection in CoreSample.
  1926.             return(errAENoSuchObject);
  1927.  
  1928.         default:                        // We don't handle requested property.
  1929.             return(errAEEventNotHandled);
  1930.     }
  1931. }
  1932.  
  1933. //----------------------------------------------------------------------------------//
  1934. //    Get the property data for the application and return it in the result parameter.//
  1935. //    The result token contains the property type in the descriptorType field, and    //
  1936. //    a nil value in the dataHandle field to represent the null application.            //
  1937. //----------------------------------------------------------------------------------//
  1938. #pragma segment Main
  1939. OSErr GetAppData(    DescType    theProperty,
  1940.                     AEDesc*        result    )        // Descriptor record to hold the property data.
  1941. {
  1942.     ProcessInfoRec            myProcessInfo;        // [pwpc]
  1943.     DescType                theType;
  1944.     short                    refNum;
  1945.     Str255                    name;
  1946.     Handle                    myHandle;
  1947.     ProcessSerialNumber        thePSN, currentProcess;
  1948.     Boolean                    isFront;
  1949.     OSErr                    err;
  1950.  
  1951.     switch (theProperty)
  1952.     {
  1953.         case pBestType:                    // Return the null descriptor representing
  1954.         case pDefaultType:                // the application.
  1955.             return(AEDuplicateDesc(&gNullDesc, result));
  1956.  
  1957.         case pClass:
  1958.             theType = cApplication;
  1959.             return(AECreateDesc(typeType,(Ptr)&theType,sizeof(DescType),result));
  1960.             
  1961.         case pName:
  1962.             // [pwpc] Clear out the name, and then call the process manager to get
  1963.             // the string for the name of our application.
  1964.             
  1965.             name[0] = 0;
  1966.             myProcessInfo.processInfoLength = sizeof(myProcessInfo); 
  1967.             myProcessInfo.processName = name;
  1968.             myProcessInfo.processAppSpec = NULL;
  1969.             
  1970.             GetCurrentProcess(¤tProcess);
  1971.             GetProcessInformation(¤tProcess, &myProcessInfo);
  1972.         
  1973.             // Create an AEDesc returning the application name string
  1974.             // returned by the process manager.
  1975.  
  1976.             return(AECreateDesc(typeChar, (Ptr)&name[1], name[0], result));
  1977.  
  1978.         case pIsFrontProcess:
  1979.             GetFrontProcess(&thePSN);
  1980.             SameProcess(&gSelfPSN, &thePSN, &isFront);
  1981.             return(AECreateDesc(typeBoolean,(Ptr)&isFront,sizeof(Boolean),result));
  1982.             
  1983.         case pVersion:
  1984.             refNum = CurResFile();            // save current resource
  1985.             UseResFile(gRefNum);            // set this resource to be current
  1986.             myHandle = (Handle)Get1Resource((ResType)'vers', 1);
  1987.               HLock(myHandle);
  1988.              err = AECreateDesc(typeVersion, *myHandle, GetHandleSize(myHandle), result);
  1989.               HUnlock(myHandle);
  1990.             UseResFile(refNum);                // reset back to resource previously set
  1991.             return(err);
  1992.  
  1993.         default:                // We don't handle the requested property.
  1994.             return(errAEEventNotHandled);
  1995.     }
  1996. }
  1997.  
  1998. //----------------------------------------------------------------------------------//
  1999. //    Create an object specifier for the window with the indicated key form.            //
  2000. //----------------------------------------------------------------------------------//
  2001. #pragma segment Main
  2002. OSErr CreateWindowObjectSpec( WindowPtr    window,
  2003.                               short        keyForm,        // index or name key form.
  2004.                                 AEDesc*    objectSpec )    // Resulting object specifier.
  2005. {
  2006.     AEDesc        data;
  2007.     Str255        title;
  2008.     long        index;
  2009.     OSErr        err;
  2010.  
  2011.     MyInitDescs(&data, kEndOfList);
  2012.     switch(keyForm)
  2013.     {
  2014.         case kNameKeyForm:                    // Object specifier with name.
  2015.             GetWTitle(window, title);
  2016.             if (!(err = AECreateDesc(typeChar, (Ptr)&title[1], title[0], &data)))                
  2017.                 err = CreateObjSpecifier(cWindow, &gNullDesc, formName, &data,
  2018.                                     false, objectSpec);
  2019.             break;
  2020.             
  2021.         case kIndexKeyForm:                    // Object specifier with index.
  2022.             index = GetWindowIndexNum(window);
  2023.             if (!(err = CreateOffsetDescriptor(index, &data)))
  2024.                 err = CreateObjSpecifier(cWindow, &gNullDesc, formAbsolutePosition, &data,
  2025.                                     false, objectSpec);
  2026.             break;
  2027.     }
  2028.     MyDisposeDescs(&data, kEndOfList);
  2029.     return(err);
  2030. }
  2031.  
  2032. //----------------------------------------------------------------------------------//
  2033. //    Check to see if there exists any additional parameters in the Apple Event.      //
  2034. //    If so, return an error to the calling routine.                                    //
  2035. //----------------------------------------------------------------------------------//
  2036. #pragma segment Main
  2037. OSErr GetMissingParams(AppleEvent*  theAppleEvent)
  2038. {
  2039.     DescType    theType;
  2040.     Size        actualSize;
  2041.     OSErr        err;
  2042.     
  2043.     err = AEGetAttributePtr(theAppleEvent, keyMissedKeywordAttr, typeWildCard,
  2044.                                 &theType, nil, 0, &actualSize);
  2045.     if (err == errAEDescNotFound)
  2046.         return(noErr);
  2047.     else
  2048.         return(errAEEventNotHandled);
  2049. }
  2050.  
  2051. //----------------------------------------------------------------------------------//
  2052. //    If a reply is expected, the error number is returned in the reply parameter.    //
  2053. //----------------------------------------------------------------------------------//
  2054. #pragma segment Main
  2055. void ReportError( AppleEvent*    reply,
  2056.                   long            err    )
  2057. {
  2058.     if (reply->dataHandle != nil && err != noErr)
  2059.         FailIfErr(AEPutParamPtr(reply,keyErrorNumber,typeLongInteger,(Ptr)&err,sizeof(long)));
  2060. }
  2061.  
  2062. //----------------------------------------------------------------------------------//
  2063. //    This routine returns the window object contained in the given object specifier.    //
  2064. //    If the resolution does not return a descriptor record of type cWindow, nil is     //
  2065. //    returned as a result.                                                            //
  2066. //----------------------------------------------------------------------------------//
  2067. #pragma segment Main
  2068. WindowPtr ResolveToWindow(AEDesc*  objectSpecifier)
  2069. {
  2070.     AEDesc        token;
  2071.     WindowPtr    window;
  2072.  
  2073.  
  2074.     MyInitDescs(&token, kEndOfList);
  2075.     window = nil;
  2076.     if (objectSpecifier->descriptorType == typeObjectSpecifier)
  2077.         if (!(AEResolve(objectSpecifier, kAEIDoMinimum, &token)))
  2078.             if (token.descriptorType == cWindow)
  2079.                 window = (WindowPtr)*((LongPtr)*(token.dataHandle));
  2080.  
  2081.     MyDisposeDescs(&token, kEndOfList);
  2082.     return(window);
  2083. }
  2084.  
  2085. //----------------------------------------------------------------------------------//
  2086. //    Retrieve the window from the null container by the key form and return its        //
  2087. //    pointer in the dataHandle field of resultToken.                                    //
  2088. //----------------------------------------------------------------------------------//
  2089. #pragma segment Main
  2090. pascal
  2091. OSErr WindowAccessor( DescType        classWanted,        // window class
  2092.                       AEDesc*        container,            // the application (null container)
  2093.                       DescType        containerClass, 
  2094.                       DescType        keyform,
  2095.                       AEDesc*        selectionData,
  2096.                       AEDesc*        resultToken,        // specified window is returned in result
  2097.                       long             theRefCon     )
  2098. {
  2099.     #pragma unused (classWanted,container,containerClass,theRefCon)
  2100.     WindowPtr        window;
  2101.     DescType        seldataType;
  2102.     Str255            title;
  2103.     long            index;
  2104.     OSErr            err;
  2105.  
  2106.     window = nil;
  2107.     err = noErr;    
  2108.     if (!gNumWindowsOpen)
  2109.         return(errAENoSuchObject);
  2110.     else
  2111.     {
  2112.         seldataType = selectionData->descriptorType;
  2113.     
  2114.         switch(keyform)
  2115.         {
  2116.             case formName:                                    // Window title.
  2117.                 if (DescToPString(selectionData,title,kMaxStrSize) != noErr)
  2118.                     return(errAECoercionFail);
  2119.                 if (!(window = GetWindowWithTitle(title)))
  2120.                     return(errAENoSuchObject);        // Window was not found.
  2121.                 break;
  2122.             
  2123.             case formAbsolutePosition:
  2124.                 if (DescToLong(selectionData,&index) != noErr)
  2125.                     return(errAECoercionFail);        // Data cannot be coerced.
  2126.                 if (!(window = GetWindowAtIndex(index)))
  2127.                     return(errAENoSuchObject);            // Window was not found.
  2128.                 break;    
  2129.             
  2130.             default:                                    // I don't handle any other key forms.
  2131.                 return(errAEEventNotHandled);
  2132.         }
  2133.     }
  2134.     return(AECreateDesc(cWindow, (Ptr)&window, sizeof(Ptr), resultToken));
  2135. }
  2136.  
  2137. //----------------------------------------------------------------------------------//
  2138. //    Return a token representing the property for the containing window.  The token    //
  2139. //    is returned with the property and window pointer.                                //
  2140. //----------------------------------------------------------------------------------//
  2141. #pragma segment Main
  2142. pascal
  2143. OSErr WindowPropertyAccessor( DescType        classWanted,        // Property class
  2144.                                 AEDesc*        container,            // Window object
  2145.                               DescType        containerClass, 
  2146.                               DescType        form,
  2147.                               AEDesc*        selectionData,
  2148.                               AEDesc*        resultToken,
  2149.                               long             theRefCon     )
  2150. {
  2151.     #pragma unused (containerClass, theRefCon)
  2152.     Ptr                window;
  2153.     DescType        propType;
  2154.     
  2155.             //    Let's make sure we're accessing a valid descriptor type.
  2156.     if ((classWanted != cProperty) || (form != formPropertyID))
  2157.         return(errAEWrongDataType);
  2158.  
  2159.     window = (Ptr)*(LongPtr)*(container->dataHandle);        // Get the window pointer.
  2160.     propType = *(LongPtr)*selectionData->dataHandle;        // Get the property type.
  2161.     return(AECreateDesc(propType, (Ptr)&window, sizeof(Ptr), resultToken)); 
  2162. }
  2163.  
  2164. //----------------------------------------------------------------------------------//
  2165. //    Return a token that contains the property type and nil to represent the null    //
  2166. //    container (the application).                                                    //
  2167. //----------------------------------------------------------------------------------//
  2168. #pragma segment Main
  2169. pascal
  2170. OSErr AppPropertyAccessor(    DescType        classWanted,            // Property class.
  2171.                               AEDesc*            container,                // Application.
  2172.                             DescType        containerClass, 
  2173.                             DescType        form,
  2174.                             AEDesc*            selectionData,
  2175.                             AEDesc*            resultToken,
  2176.                             long             theRefCon     )
  2177. {    
  2178.     #pragma unused (container,containerClass,theRefCon)
  2179.     DescType        propType;
  2180.     long            nilValue;
  2181.     
  2182.             //    Let's make sure we're accessing a valid descriptor type.
  2183.     if ((classWanted != cProperty) || (form != formPropertyID))
  2184.         return(errAEWrongDataType);
  2185.     nilValue = nil;        
  2186.     propType = *(LongPtr)*selectionData->dataHandle;            // Get the property type.
  2187.     return(AECreateDesc(propType, (Ptr)&nilValue, sizeof(long), resultToken)); 
  2188. }
  2189.  
  2190. //----------------------------------------------------------------------------------//
  2191. //    Returns the window with the given title if found.  Otherwise, nil is returned.    //
  2192. //    Use WindowList in order to find windows that may be invisible.                    //
  2193. //----------------------------------------------------------------------------------//
  2194. #pragma segment Main
  2195. WindowPtr GetWindowWithTitle( ConstStr255Param  titleToFind )
  2196. {
  2197.     WindowPeek    window;
  2198.     Str255        thisTitle;
  2199.     
  2200. #ifdef  THINK_C
  2201.     window = (WindowPeek)LMGetWindowList();    // WindowList finds invisible windows as well.
  2202. #else
  2203.     window = *(PeekPtr)LMGetWindowList();        // WindowList finds invisible windows as well.
  2204. #endif
  2205.     
  2206.     while (window)
  2207.     {
  2208.         GetWTitle((WindowPtr)window, thisTitle);
  2209.         if (EqualString(thisTitle, titleToFind, false, false))
  2210.             return((WindowPtr)window);
  2211.         window = window->nextWindow;
  2212.     }
  2213.     return(nil);
  2214. }
  2215.  
  2216. //----------------------------------------------------------------------------------//
  2217. //    Search all windows (including invisible), and return the window at the given     //
  2218. //    index if found. Otherwise, nil is returned. This routine also handles negative    //
  2219. //    indices which indicates that the offset    is from the end of the container.        //                                    //
  2220. //----------------------------------------------------------------------------------//
  2221. #pragma segment Main
  2222. WindowPtr GetWindowAtIndex(long  index)
  2223. {
  2224.     WindowPeek    window;
  2225.     short        count;
  2226.     
  2227.     index = index < 0 ? gNumWindowsOpen+index+1 : index;
  2228.     count = 1;
  2229.     
  2230. #ifdef  THINK_C
  2231.     window = (WindowPeek)LMGetWindowList();    // WindowList finds invisible windows as well.
  2232. #else
  2233.     window = *(PeekPtr)LMGetWindowList();        // WindowList finds invisible windows as well.
  2234. #endif
  2235.  
  2236.     while (window)
  2237.     {
  2238.         if (count == index)
  2239.             return((WindowPtr)window);
  2240.         window = window->nextWindow;
  2241.         count++;
  2242.     }
  2243.     return(nil);
  2244. }
  2245.  
  2246. //----------------------------------------------------------------------------------//
  2247. //    Returns the index number of the given window, where 1 is the frontmost.            //
  2248. //----------------------------------------------------------------------------------//
  2249. #pragma segment Main
  2250. long GetWindowIndexNum(WindowPtr myWindow)
  2251. {
  2252.     WindowPeek    thisWindow;
  2253.     long        index;
  2254.     
  2255. #ifdef  THINK_C
  2256.     thisWindow = (WindowPeek)LMGetWindowList();        // Compilers are so much fun!!.
  2257. #else
  2258.     thisWindow = *(PeekPtr)LMGetWindowList();            // WindowList finds invisible windows as well.
  2259. #endif
  2260.  
  2261.     index = 1;
  2262.     
  2263.     while (thisWindow)
  2264.     {
  2265.         if (thisWindow == (WindowPeek)myWindow)        // [pwpc]
  2266.             return(index);
  2267.         thisWindow = thisWindow->nextWindow;
  2268.         index++;
  2269.     }
  2270.     return(nil);
  2271. }
  2272.  
  2273. //----------------------------------------------------------------------------------//
  2274. //    This routine returns the bounds of a given window. Special calculations are        //
  2275. //    performed when the bounds is invalid (i.e., the window is hidden).                //
  2276. //----------------------------------------------------------------------------------//
  2277. #pragma segment Main
  2278. Rect DoGetWindowBounds(WindowPtr window)
  2279. {
  2280.     Rect    portRect, bitMapRect, bounds;
  2281.     
  2282.     bounds = (*((WindowPeek)window)->contRgn)->rgnBBox;        // check the content region.
  2283.     if (bounds.top == 0 && bounds.left == 0 &&
  2284.         bounds.bottom == 0 && bounds.right == 0)
  2285.     {
  2286.         portRect = window->portRect;
  2287.         bitMapRect = window->portBits.bounds;
  2288.         
  2289.         bounds.top =  portRect.top - bitMapRect.top;
  2290.         bounds.left = portRect.left - bitMapRect.left;
  2291.         bounds.bottom = portRect.bottom - bitMapRect.top;
  2292.         bounds.right = portRect.right - bitMapRect.left;
  2293.     }
  2294.     return(bounds);
  2295. }
  2296.  
  2297. //----------------------------------------------------------------------------------//
  2298. #pragma    segment Initialize
  2299. void InitAEHandlers()
  2300. {
  2301.     AEInstallEventHandler(kCoreEventClass,kAEOpenApplication,NewAEEventHandlerProc(HandleOpenApp), nil,false);
  2302.     AEInstallEventHandler(kCoreEventClass,kAEOpenDocuments,NewAEEventHandlerProc(DummyHandler), nil,false);
  2303.     AEInstallEventHandler(kCoreEventClass,kAEPrintDocuments,NewAEEventHandlerProc(DummyHandler), nil,false);
  2304.     AEInstallEventHandler(kCoreEventClass, kAEQuitApplication, NewAEEventHandlerProc(HandleQuitApp), nil, false);
  2305.     AEInstallEventHandler(kAECoreSuite, kAEClone, NewAEEventHandlerProc(HandleClone), nil, false);
  2306.     AEInstallEventHandler(kAECoreSuite, kAEClose, NewAEEventHandlerProc(HandleClose), nil, false);
  2307.     AEInstallEventHandler(kAECoreSuite, kAECountElements, NewAEEventHandlerProc(HandleCountElements), nil, false);
  2308.     AEInstallEventHandler(kAECoreSuite, kAECreateElement, NewAEEventHandlerProc(HandleCreateElement), nil, false);
  2309.     AEInstallEventHandler(kAECoreSuite, kAEDelete, NewAEEventHandlerProc(HandleClose), nil, false);
  2310.     AEInstallEventHandler(kAECoreSuite, kAEDoObjectsExist, NewAEEventHandlerProc(HandleDoObjectsExist), nil, false);
  2311.     AEInstallEventHandler(kAECoreSuite, kAEGetData, NewAEEventHandlerProc(HandleGetData), kAEGetData, false);
  2312.     AEInstallEventHandler(kAECoreSuite, kAEGetDataSize, NewAEEventHandlerProc(HandleGetData), kAEGetDataSize, false);
  2313.     AEInstallEventHandler(kAECoreSuite, kAEGetClassInfo, NewAEEventHandlerProc(DummyHandler), nil, false);
  2314.     AEInstallEventHandler(kAECoreSuite, kAEGetEventInfo, NewAEEventHandlerProc(DummyHandler), nil, false);
  2315.     AEInstallEventHandler(kAECoreSuite, kAEMove, NewAEEventHandlerProc(HandleMove), nil, false);
  2316.     AEInstallEventHandler(kAECoreSuite, kAESave, NewAEEventHandlerProc(DummyHandler), nil, false);
  2317.     AEInstallEventHandler(kAECoreSuite, kAESetData, NewAEEventHandlerProc(HandleSetData), nil, false);
  2318.  
  2319.     AEObjectInit();
  2320.     AEInstallObjectAccessor(cWindow, typeNull, NewOSLAccessorProc(WindowAccessor), nil, false);
  2321.     AEInstallObjectAccessor(cProperty, typeNull, NewOSLAccessorProc(AppPropertyAccessor), nil, false);
  2322.     AEInstallObjectAccessor(cProperty, cWindow, NewOSLAccessorProc(WindowPropertyAccessor), nil, false);
  2323. }
  2324.